<commit_before>#include "pch.h"
#include "jnc_io_FileStream.h"

namespace jnc {
namespace io {

//.............................................................................

FileStream::FileStream ()
{
	m_runtime = rt::getCurrentThreadRuntime ();
	m_ioFlags = 0;
#if (_AXL_ENV == AXL_ENV_WIN)
	m_incomingDataSize = 0;
#endif
	m_isOpen = false;
	m_syncId = 0;
	m_fileStreamKind = FileStreamKind_Unknown;
}

void
FileStream::wakeIoThread ()
{
#if (_AXL_ENV == AXL_ENV_WIN)
	m_ioThreadEvent.signal ();
#else
	m_selfPipe.write (" ", 1);
#endif
}

bool
AXL_CDECL
FileStream::open (
	rt::DataPtr namePtr,
	uint_t openFlags
	)
{
	bool result;

	close ();

#if (_AXL_ENV == AXL_ENV_POSIX)
	// force asynchronous and restore blocking mode later

	result =
		m_file.open ((const char*) namePtr.m_p, openFlags | axl::io::FileFlag_Asynchronous) &&
		m_file.m_file.setBlockingMode (true);
#else
	result = m_file.open ((const char*) namePtr.m_p, openFlags | axl::io::FileFlag_Asynchronous);
#endif

	if (!result)
	{
		ext::propagateLastError ();
		return false;
	}

	m_isOpen = true;

#if (_AXL_ENV == AXL_ENV_WIN)

	dword_t type = ::GetFileType (m_file.m_file);
	switch (type)
	{
	case FILE_TYPE_CHAR:
		m_fileStreamKind = FileStreamKind_Serial;
		break;

	case FILE_TYPE_DISK:
		m_fileStreamKind = FileStreamKind_Disk;
		break;

	case FILE_TYPE_PIPE:
		m_fileStreamKind = FileStreamKind_Pipe;
		break;

	default:
		m_fileStreamKind = FileStreamKind_Unknown;
	};

	m_ioThreadEvent.reset ();
	m_readBuffer.setCount (Const_ReadBufferSize);
	m_incomingDataSize = 0;
#elif (_AXL_ENV == AXL_ENV_POSIX)
	m_selfPipe.create ();
#endif

	m_ioFlags = 0;
	m_ioThread.start ();
	return true;
}

void
AXL_CDECL
FileStream::close ()
{
	if (!m_file.isOpen ())
		return;

	m_ioLock.lock ();
	m_ioFlags |= IoFlag_Closing;
	wakeIoThread ();
	m_ioLock.unlock ();

	rt::enterWaitRegion (m_runtime);
	m_ioThread.waitAndClose ();
	rt::leaveWaitRegion (m_runtime);

#if (_AXL_ENV == AXL_ENV_POSIX)
	m_selfPipe.close ();
#endif

	m_file.close ();
	m_ioFlags = 0;
#if (_AXL_ENV == AXL_ENV_WIN)
	m_incomingDataSize = 0;
#endif
	m_isOpen = false;
	m_syncId++;
}

bool
AXL_CDECL
FileStream::clear ()
{
	return m_file.setSize (0);
}

void
AXL_CDECL
FileStream::firePendingEvents ()
{
}

void
FileStream::fireFileStreamEvent (
	FileStreamEventKind eventKind,
	const err::ErrorHdr* error
	)
{
	JNC_BEGIN_CALL_SITE_NO_COLLECT (m_runtime, true);

	rt::DataPtr paramsPtr = rt::createData <FileStreamEventParams> (m_runtime);
	FileStreamEventParams* params = (FileStreamEventParams*) paramsPtr.m_p;
	params->m_eventKind = eventKind;
	params->m_syncId = m_syncId;

	if (error)
		params->m_errorPtr = rt::memDup (error, error->m_size);

	rt::callMulticast (m_onFileStreamEvent, paramsPtr);

	JNC_END_CALL_SITE ();
}

#if (_AXL_ENV == AXL_ENV_WIN)

size_t
AXL_CDECL
FileStream::read (
	rt::DataPtr ptr,
	size_t size
	)
{
	m_ioLock.lock ();
	if (m_ioFlags & IoFlag_IncomingData)
	{
		size_t result = readImpl (ptr.m_p, size);
		wakeIoThread ();
		m_ioLock.unlock ();

		return result;
	}
	else
	{
		Read read;
		read.m_buffer = ptr.m_p;
		read.m_size = size;
		m_readList.insertTail (&read);
		wakeIoThread ();
		m_ioLock.unlock ();

		rt::enterWaitRegion (m_runtime);
		read.m_completionEvent.wait ();
		rt::leaveWaitRegion (m_runtime);

		if (read.m_result == -1)
			ext::setError (read.m_error);

		return read.m_result;
	}
}

size_t
FileStream::readImpl (
	void* p,
	size_t size
	)
{
	ASSERT (m_incomingDataSize);

	size_t copySize;

	if (size < m_incomingDataSize)
	{
		copySize = size;
		m_incomingDataSize -= size;
		m_ioFlags |= IoFlag_RemainingData;
		memcpy (p, m_readBuffer, copySize);
		memmove (m_readBuffer, m_readBuffer + copySize, m_incomingDataSize);
	}
	else
	{
		copySize = m_incomingDataSize;
		m_incomingDataSize = 0;
		m_ioFlags &= ~IoFlag_IncomingData;
		memcpy (p, m_readBuffer, copySize);
	}

	return copySize;
}

size_t
AXL_CDECL
FileStream::write (
	rt::DataPtr ptr,
	size_t size
	)
{
	sys::Event completionEvent;
	OVERLAPPED overlapped = { 0 };
	overlapped.hEvent = completionEvent.m_event;

	if (m_fileStreamKind == FileStreamKind_Disk)
	{
		uint64_t offset = m_file.getSize ();
		overlapped.Offset = (DWORD) offset;
		overlapped.OffsetHigh = (DWORD) (offset >> 32);
	}

	bool_t result = m_file.m_file.write (ptr.m_p, size, NULL, &overlapped);
	size_t actualSize = result ? m_file.m_file.getOverlappedResult (&overlapped) : -1;

	if (actualSize == -1)
		ext::propagateLastError ();

	return actualSize;
}

void
FileStream::ioThreadFunc ()
{
	ASSERT (m_file.isOpen ());

	readLoop ();

	// wait for close, cancell all incoming reads

	for (;;)
	{
		m_ioLock.lock ();

		while (!m_readList.isEmpty ())
		{
			Read* read = m_readList.removeHead ();
			read->m_result = -1;
			read->m_error = err::Error (ERROR_CANCELLED);
			read->m_completionEvent.signal ();
		}

		if (m_ioFlags & IoFlag_Closing)
		{
			m_ioLock.unlock ();
			break;
		}

		m_ioLock.unlock ();

		m_ioThreadEvent.wait ();
	}
}

void
FileStream::readLoop ()
{
	sys::Event completionEvent;

	HANDLE waitTable [] =
	{
		m_ioThreadEvent.m_event,
		completionEvent.m_event,
	};

	uint64_t offset = 0;

	for (;;)
	{
		Read* read = NULL;
		void* readBuffer;
		size_t readSize;

		m_ioLock.lock ();

		if (m_ioFlags & IoFlag_Closing)
		{
			m_ioLock.unlock ();
			break;
		}

		if (m_ioFlags & IoFlag_RemainingData)
		{
			ASSERT (m_ioFlags & IoFlag_IncomingData);

			if (!m_readList.isEmpty ())
			{
				read = m_readList.removeHead ();
				readImpl (read->m_buffer, read->m_size);
			}
			else
			{
				fireFileStreamEvent (FileStreamEventKind_IncomingData);
			}

			m_ioFlags &= ~IoFlag_RemainingData;
			m_ioLock.unlock ();
			continue;
		}

		if (!m_readList.isEmpty ())
		{
			read = m_readList.removeHead ();
			readBuffer = read->m_buffer;
			readSize = read->m_size;
		}
		else if (!(m_ioFlags & IoFlag_IncomingData))
		{
			ASSERT (m_incomingDataSize == 0);
			readBuffer = m_readBuffer;
			readSize = m_readBuffer.getCount ();
		}
		else
		{
			readBuffer = NULL;
		}

		m_ioLock.unlock ();

		if (!readBuffer)
		{
			DWORD waitResult = ::WaitForSingleObject (m_ioThreadEvent.m_event, INFINITE);
			if (waitResult == WAIT_FAILED)
			{
				err::Error error = err::getLastSystemErrorCode ();
				fireFileStreamEvent (FileStreamEventKind_IoError, error);
				return;
			}
		}
		else
		{
			OVERLAPPED overlapped = { 0 };

			overlapped.hEvent = completionEvent.m_event;
			overlapped.Offset = (DWORD) offset;
			overlapped.OffsetHigh = (DWORD) (offset >> 32);

			bool_t result = m_file.m_file.read (readBuffer, readSize, NULL, &overlapped);
			if (!result)
			{
				if (read)
				{
					read->m_result = -1;
					read->m_error = err::getLastError ();
					read->m_completionEvent.signal ();
				}

				break;
			}

			for (;;)
			{
				DWORD waitResult = ::WaitForMultipleObjects (2, waitTable, false, INFINITE);
				if (waitResult == WAIT_FAILED)
				{
					err::Error error = err::getLastSystemErrorCode ();
					fireFileStreamEvent (FileStreamEventKind_IoError, error);
					return;
				}

				m_ioLock.lock ();

				if (m_ioFlags & IoFlag_Closing)
				{
					m_ioLock.unlock ();
					break;
				}

				m_ioLock.unlock ();

				if (waitResult == WAIT_OBJECT_0 + 1)
					break;
			}

			readSize = m_file.m_file.getOverlappedResult (&overlapped);
			if (readSize == -1)
			{
				err::Error error = err::getLastError ();

				if (read)
				{
					read->m_result = -1;
					read->m_error = error;
					read->m_completionEvent.signal ();
				}

				fireFileStreamEvent (FileStreamEventKind_IoError, error);
				return;
			}

			if (read)
			{
				read->m_result = readSize;
				read->m_completionEvent.signal ();
			}
			else
			{
				m_ioLock.lock ();
				ASSERT (!(m_ioFlags & IoFlag_IncomingData));
				if (readSize)
				{
					m_ioFlags |= IoFlag_IncomingData;
					m_incomingDataSize = readSize;
				}

				m_ioLock.unlock ();

				if (readSize)
				{
					fireFileStreamEvent (FileStreamEventKind_IncomingData);
				}
				else
				{
					fireFileStreamEvent (FileStreamEventKind_Eof);
					return;
				}
			}

			offset += readSize; // advance offset
		}
	}
}

#elif (_AXL_ENV == AXL_ENV_POSIX)

size_t
AXL_CDECL
FileStream::read (
	rt::DataPtr ptr,
	size_t size
	)
{
	size_t result = m_file.read (ptr.m_p, size);

	m_ioLock.lock ();
	m_ioFlags &= ~IoFlag_IncomingData;
	wakeIoThread ();
	m_ioLock.unlock ();

	return result;
}

size_t
AXL_CDECL
FileStream::write (
	rt::DataPtr ptr,
	size_t size
	)
{
	return m_file.write (ptr.m_p, size);
}

void
FileStream::ioThreadFunc ()
{
	ASSERT (m_file.isOpen ());

	int result;
	int selectFd = AXL_MAX (m_file.m_file, m_selfPipe.m_readFile) + 1;

	// read/write loop

	for (;;)
	{
		fd_set readSet = { 0 };

		FD_SET (m_selfPipe.m_readFile, &readSet);

		m_ioLock.lock ();

		if (m_ioFlags & IoFlag_Closing)
		{
			m_ioLock.unlock ();
			break;
		}

		if (!(m_ioFlags & IoFlag_IncomingData)) // don't re-issue select if not handled yet
			FD_SET (m_file.m_file, &readSet);

		m_ioLock.unlock ();

		result = select (selectFd, &readSet, NULL, NULL, NULL);
		if (result == -1)
			break;

		if (FD_ISSET (m_selfPipe.m_readFile, &readSet))
		{
			char buffer [256];
			m_selfPipe.read (buffer, sizeof (buffer));
		}

		if (FD_ISSET (m_file.m_file, &readSet))
		{
			size_t incomingDataSize = m_file.m_file.getIncomingDataSize ();
			if (incomingDataSize == -1 || !incomingDataSize) // error or end-of-file
			{
				fireFileStreamEvent (FileStreamEventKind_Eof);
				break;
			}

			m_ioLock.lock ();
			ASSERT (!(m_ioFlags & IoFlag_IncomingData));
			m_ioFlags |= IoFlag_IncomingData;
			m_ioLock.unlock ();

			fireFileStreamEvent (FileStreamEventKind_IncomingData);
		}
	}
}
#endif

//.............................................................................

} // namespace io
} // namespace jnc
<commit_msg>[ioninja] critical bugfix: FileStream hang on close<commit_after>#include "pch.h"
#include "jnc_io_FileStream.h"

namespace jnc {
namespace io {

//.............................................................................

FileStream::FileStream ()
{
	m_runtime = rt::getCurrentThreadRuntime ();
	m_ioFlags = 0;
#if (_AXL_ENV == AXL_ENV_WIN)
	m_incomingDataSize = 0;
#endif
	m_isOpen = false;
	m_syncId = 0;
	m_fileStreamKind = FileStreamKind_Unknown;
}

void
FileStream::wakeIoThread ()
{
#if (_AXL_ENV == AXL_ENV_WIN)
	m_ioThreadEvent.signal ();
#else
	m_selfPipe.write (" ", 1);
#endif
}

bool
AXL_CDECL
FileStream::open (
	rt::DataPtr namePtr,
	uint_t openFlags
	)
{
	bool result;

	close ();

#if (_AXL_ENV == AXL_ENV_POSIX)
	// force asynchronous and restore blocking mode later

	result =
		m_file.open ((const char*) namePtr.m_p, openFlags | axl::io::FileFlag_Asynchronous) &&
		m_file.m_file.setBlockingMode (true);
#else
	result = m_file.open ((const char*) namePtr.m_p, openFlags | axl::io::FileFlag_Asynchronous);
#endif

	if (!result)
	{
		ext::propagateLastError ();
		return false;
	}

	m_isOpen = true;

#if (_AXL_ENV == AXL_ENV_WIN)

	dword_t type = ::GetFileType (m_file.m_file);
	switch (type)
	{
	case FILE_TYPE_CHAR:
		m_fileStreamKind = FileStreamKind_Serial;
		break;

	case FILE_TYPE_DISK:
		m_fileStreamKind = FileStreamKind_Disk;
		break;

	case FILE_TYPE_PIPE:
		m_fileStreamKind = FileStreamKind_Pipe;
		break;

	default:
		m_fileStreamKind = FileStreamKind_Unknown;
	};

	m_ioThreadEvent.reset ();
	m_readBuffer.setCount (Const_ReadBufferSize);
	m_incomingDataSize = 0;
#elif (_AXL_ENV == AXL_ENV_POSIX)
	m_selfPipe.create ();
#endif

	m_ioFlags = 0;
	m_ioThread.start ();
	return true;
}

void
AXL_CDECL
FileStream::close ()
{
	if (!m_file.isOpen ())
		return;

	m_ioLock.lock ();
	m_ioFlags |= IoFlag_Closing;
	wakeIoThread ();
	m_ioLock.unlock ();

	rt::enterWaitRegion (m_runtime);
	m_ioThread.waitAndClose ();
	rt::leaveWaitRegion (m_runtime);

#if (_AXL_ENV == AXL_ENV_POSIX)
	m_selfPipe.close ();
#endif

	m_file.close ();
	m_ioFlags = 0;
#if (_AXL_ENV == AXL_ENV_WIN)
	m_incomingDataSize = 0;
#endif
	m_isOpen = false;
	m_syncId++;
}

bool
AXL_CDECL
FileStream::clear ()
{
	return m_file.setSize (0);
}

void
AXL_CDECL
FileStream::firePendingEvents ()
{
}

void
FileStream::fireFileStreamEvent (
	FileStreamEventKind eventKind,
	const err::ErrorHdr* error
	)
{
	JNC_BEGIN_CALL_SITE_NO_COLLECT (m_runtime, true);

	rt::DataPtr paramsPtr = rt::createData <FileStreamEventParams> (m_runtime);
	FileStreamEventParams* params = (FileStreamEventParams*) paramsPtr.m_p;
	params->m_eventKind = eventKind;
	params->m_syncId = m_syncId;

	if (error)
		params->m_errorPtr = rt::memDup (error, error->m_size);

	rt::callMulticast (m_onFileStreamEvent, paramsPtr);

	JNC_END_CALL_SITE ();
}

#if (_AXL_ENV == AXL_ENV_WIN)

size_t
AXL_CDECL
FileStream::read (
	rt::DataPtr ptr,
	size_t size
	)
{
	m_ioLock.lock ();
	if (m_ioFlags & IoFlag_IncomingData)
	{
		size_t result = readImpl (ptr.m_p, size);
		wakeIoThread ();
		m_ioLock.unlock ();

		return result;
	}
	else
	{
		Read read;
		read.m_buffer = ptr.m_p;
		read.m_size = size;
		m_readList.insertTail (&read);
		wakeIoThread ();
		m_ioLock.unlock ();

		rt::enterWaitRegion (m_runtime);
		read.m_completionEvent.wait ();
		rt::leaveWaitRegion (m_runtime);

		if (read.m_result == -1)
			ext::setError (read.m_error);

		return read.m_result;
	}
}

size_t
FileStream::readImpl (
	void* p,
	size_t size
	)
{
	ASSERT (m_incomingDataSize);

	size_t copySize;

	if (size < m_incomingDataSize)
	{
		copySize = size;
		m_incomingDataSize -= size;
		m_ioFlags |= IoFlag_RemainingData;
		memcpy (p, m_readBuffer, copySize);
		memmove (m_readBuffer, m_readBuffer + copySize, m_incomingDataSize);
	}
	else
	{
		copySize = m_incomingDataSize;
		m_incomingDataSize = 0;
		m_ioFlags &= ~IoFlag_IncomingData;
		memcpy (p, m_readBuffer, copySize);
	}

	return copySize;
}

size_t
AXL_CDECL
FileStream::write (
	rt::DataPtr ptr,
	size_t size
	)
{
	sys::Event completionEvent;
	OVERLAPPED overlapped = { 0 };
	overlapped.hEvent = completionEvent.m_event;

	if (m_fileStreamKind == FileStreamKind_Disk)
	{
		uint64_t offset = m_file.getSize ();
		overlapped.Offset = (DWORD) offset;
		overlapped.OffsetHigh = (DWORD) (offset >> 32);
	}

	bool_t result = m_file.m_file.write (ptr.m_p, size, NULL, &overlapped);
	size_t actualSize = result ? m_file.m_file.getOverlappedResult (&overlapped) : -1;

	if (actualSize == -1)
		ext::propagateLastError ();

	return actualSize;
}

void
FileStream::ioThreadFunc ()
{
	ASSERT (m_file.isOpen ());

	readLoop ();

	// wait for close, cancell all incoming reads

	for (;;)
	{
		m_ioLock.lock ();

		while (!m_readList.isEmpty ())
		{
			Read* read = m_readList.removeHead ();
			read->m_result = -1;
			read->m_error = err::Error (ERROR_CANCELLED);
			read->m_completionEvent.signal ();
		}

		if (m_ioFlags & IoFlag_Closing)
		{
			m_ioLock.unlock ();
			break;
		}

		m_ioLock.unlock ();

		m_ioThreadEvent.wait ();
	}
}

void
FileStream::readLoop ()
{
	sys::Event completionEvent;

	HANDLE waitTable [] =
	{
		m_ioThreadEvent.m_event,
		completionEvent.m_event,
	};

	uint64_t offset = 0;

	for (;;)
	{
		Read* read = NULL;
		void* readBuffer;
		size_t readSize;

		m_ioLock.lock ();

		if (m_ioFlags & IoFlag_Closing)
		{
			m_ioLock.unlock ();
			break;
		}

		if (m_ioFlags & IoFlag_RemainingData)
		{
			ASSERT (m_ioFlags & IoFlag_IncomingData);

			if (!m_readList.isEmpty ())
			{
				read = m_readList.removeHead ();
				readImpl (read->m_buffer, read->m_size);
			}
			else
			{
				fireFileStreamEvent (FileStreamEventKind_IncomingData);
			}

			m_ioFlags &= ~IoFlag_RemainingData;
			m_ioLock.unlock ();
			continue;
		}

		if (!m_readList.isEmpty ())
		{
			read = m_readList.removeHead ();
			readBuffer = read->m_buffer;
			readSize = read->m_size;
		}
		else if (!(m_ioFlags & IoFlag_IncomingData))
		{
			ASSERT (m_incomingDataSize == 0);
			readBuffer = m_readBuffer;
			readSize = m_readBuffer.getCount ();
		}
		else
		{
			readBuffer = NULL;
		}

		m_ioLock.unlock ();

		if (!readBuffer)
		{
			DWORD waitResult = ::WaitForSingleObject (m_ioThreadEvent.m_event, INFINITE);
			if (waitResult == WAIT_FAILED)
			{
				err::Error error = err::getLastSystemErrorCode ();
				fireFileStreamEvent (FileStreamEventKind_IoError, error);
				return;
			}
		}
		else
		{
			OVERLAPPED overlapped = { 0 };

			overlapped.hEvent = completionEvent.m_event;
			overlapped.Offset = (DWORD) offset;
			overlapped.OffsetHigh = (DWORD) (offset >> 32);

			bool_t result = m_file.m_file.read (readBuffer, readSize, NULL, &overlapped);
			if (!result)
			{
				if (read)
				{
					read->m_result = -1;
					read->m_error = err::getLastError ();
					read->m_completionEvent.signal ();
				}

				break;
			}

			for (;;) // cycle is needed case main thread can add new reads to m_readList
			{
				DWORD waitResult = ::WaitForMultipleObjects (2, waitTable, false, INFINITE);
				if (waitResult == WAIT_FAILED)
				{
					err::Error error = err::getLastSystemErrorCode ();
					fireFileStreamEvent (FileStreamEventKind_IoError, error);
					return;
				}

				m_ioLock.lock ();

				if (m_ioFlags & IoFlag_Closing)
				{
					m_ioLock.unlock ();
					return;
				}

				m_ioLock.unlock ();

				if (waitResult == WAIT_OBJECT_0 + 1)
					break;
			}

			readSize = m_file.m_file.getOverlappedResult (&overlapped);
			if (readSize == -1)
			{
				err::Error error = err::getLastError ();

				if (read)
				{
					read->m_result = -1;
					read->m_error = error;
					read->m_completionEvent.signal ();
				}

				fireFileStreamEvent (FileStreamEventKind_IoError, error);
				return;
			}

			if (read)
			{
				read->m_result = readSize;
				read->m_completionEvent.signal ();
			}
			else
			{
				m_ioLock.lock ();
				ASSERT (!(m_ioFlags & IoFlag_IncomingData));
				if (readSize)
				{
					m_ioFlags |= IoFlag_IncomingData;
					m_incomingDataSize = readSize;
				}

				m_ioLock.unlock ();

				if (readSize)
				{
					fireFileStreamEvent (FileStreamEventKind_IncomingData);
				}
				else
				{
					fireFileStreamEvent (FileStreamEventKind_Eof);
					return;
				}
			}

			offset += readSize; // advance offset
		}
	}
}

#elif (_AXL_ENV == AXL_ENV_POSIX)

size_t
AXL_CDECL
FileStream::read (
	rt::DataPtr ptr,
	size_t size
	)
{
	size_t result = m_file.read (ptr.m_p, size);

	m_ioLock.lock ();
	m_ioFlags &= ~IoFlag_IncomingData;
	wakeIoThread ();
	m_ioLock.unlock ();

	return result;
}

size_t
AXL_CDECL
FileStream::write (
	rt::DataPtr ptr,
	size_t size
	)
{
	return m_file.write (ptr.m_p, size);
}

void
FileStream::ioThreadFunc ()
{
	ASSERT (m_file.isOpen ());

	int result;
	int selectFd = AXL_MAX (m_file.m_file, m_selfPipe.m_readFile) + 1;

	// read/write loop

	for (;;)
	{
		fd_set readSet = { 0 };

		FD_SET (m_selfPipe.m_readFile, &readSet);

		m_ioLock.lock ();

		if (m_ioFlags & IoFlag_Closing)
		{
			m_ioLock.unlock ();
			break;
		}

		if (!(m_ioFlags & IoFlag_IncomingData)) // don't re-issue select if not handled yet
			FD_SET (m_file.m_file, &readSet);

		m_ioLock.unlock ();

		result = select (selectFd, &readSet, NULL, NULL, NULL);
		if (result == -1)
			break;

		if (FD_ISSET (m_selfPipe.m_readFile, &readSet))
		{
			char buffer [256];
			m_selfPipe.read (buffer, sizeof (buffer));
		}

		if (FD_ISSET (m_file.m_file, &readSet))
		{
			size_t incomingDataSize = m_file.m_file.getIncomingDataSize ();
			if (incomingDataSize == -1 || !incomingDataSize) // error or end-of-file
			{
				fireFileStreamEvent (FileStreamEventKind_Eof);
				break;
			}

			m_ioLock.lock ();
			ASSERT (!(m_ioFlags & IoFlag_IncomingData));
			m_ioFlags |= IoFlag_IncomingData;
			m_ioLock.unlock ();

			fireFileStreamEvent (FileStreamEventKind_IncomingData);
		}
	}
}
#endif

//.............................................................................

} // namespace io
} // namespace jnc
<|endoftext|>


<commit_before>#include "ofApp.h"
#include <opencv2/opencv.hpp>

using namespace ofxCv;
using namespace cv;

void ofApp::onCharacterReceived(SSHKeyListenerEventData& e)
{
	keyPressed((int)e.character);
}
//--------------------------------------------------------------
void ofApp::setup(){

    ofLog() << "RPid " << RPiId;
    gui.setup("panel");
    gui.setPosition(650,10);
    gui.add(cutDown.set( "cutDown", 110, 1, 255 ));
    gui.add(fps.set("fps", 15, 1, 30));
    gui.add(learningTime.set("learningTime",100,1,1000));
    gui.add(backgroundThreshold.set("backgroundThreshold",20,1,300));
    gui.add(erodeFactor.set("erodeFactor",0,0,3));
    gui.add(dilateFactor.set("dilateFactor",2,0,3));
    gui.add(medianBlurFactor.set("medianBlur",3,0,5));
    gui.add(minContourArea.set("minContourArea",20, 5, 40));
    gui.add(maxContourArea.set("maxContourArea", 300, 40, 160*120)); // one third of the screen.
    gui.add(maxContours.set("maxContours", 5, 1, 10));
    ofSetFrameRate(fps);
    //experimenting
    gui.add(exposureCompensation.set("exposure compensation",0,-10,10));
    gui.add(exposureMeteringMode.set("exposure metering mode",0,0,4));
    gui.add(exposureMode.set("exposure mode",0,0,13));
    gui.add(shutterSpeed.set("shutter speed",0,0,330000));//(in micro seconds)
    gui.add(awbMode.set("AutoWhiteBalance mode",0,0,10));
    gui.add(roiX.set("ROI x",0,0,1));
    gui.add(roiY.set("ROI y",0,0,1));
    gui.add(roiW.set("ROI w",1,0,1));
    gui.add(roiH.set("ROI h",1,0,1));
    //experimenting off
    filename_save = "RPi_" + RPiId + "_settings.xml";

    if(ofFile::doesFileExist(filename_save)){
        ofLog(OF_LOG_NOTICE)<< "loading from file" + filename_save << endl;
        gui.loadFromFile(filename_save);
    }

    consoleListener.setup(this);
    consoleListener.startThread(false, false);

    background.setLearningTime(learningTime);
    background.setThresholdValue(backgroundThreshold);

	// if we set setIgnoreForeground to true
	// we will have problems in case of rain.
//	background.setIgnoreForeground(true);

    fps.addListener(this, &ofApp::fpsChanged);
    learningTime.addListener(this, &ofApp::learningTimeChanged);
    backgroundThreshold.addListener(this, &ofApp::backgroundThresholdChanged);

#ifdef __arm__
    cam.setup(160,120,false);//setup camera (w,h,color = true,gray = false);
    cam.setExposureMode(MMAL_PARAM_EXPOSUREMODE_FIXEDFPS);

	// one of these two gives black during night time
//    cam.setExposureCompensation(0);
//    cam.setAWBMode(MMAL_PARAM_AWBMODE_OFF);

#else
    cam.initGrabber(160,120);
#endif

    //sender.setup("192.168.255.255", 8000);
    sender.setup("192.168.1.3", 8000);
 	receiver.setup(OSC_PORT);
}

static int framenr = 1;

//--------------------------------------------------------------
void ofApp::update(){
    sent_blobs = 0;
	framenr++;

	// IF running from RPi
#ifdef __arm__
    frame = Mat(cam.grab());
    stringstream ss;
    ss << "rpi_" << RPiId << ".png";
    if(framenr % 100 == 0) {
      toOf(frame,tosave);

      ofSaveImage(tosave, ss.str());
    }

	// IF running from Computer
#else
    string filename;
    filename = "images/file" + ofToString(framenr) + ".png";
    image.loadImage(filename);
    image.rotate90(2);
	image.setImageType(OF_IMAGE_COLOR);
    frame = toCv(image);
#endif

    if (framenr == 130) {
        background.reset();
    }

    if (!frame.empty()) {

        threshold( frame, frame, cutDown, 255, 2 );

        background.update(frame, thresholded);
        thresholded.update();

        frameProcessed = toCv(thresholded);
        medianBlur ( frameProcessed, frameProcessed, medianBlurFactor );
        erode( frameProcessed, frameProcessed, erodeFactor );
        dilate( frameProcessed, frameProcessed, dilateFactor );

        toOf(frameProcessed, pix);
        grayImage.setFromPixels(pix);

        contourFinder.findContours(grayImage, minContourArea, maxContourArea, maxContours, true); // find holes

        ofxOscMessage numContours;
        stringstream addr;
        addr << "/RPi_" << RPiId << "/total_contours/";
        numContours.setAddress(addr.str());
        //numContours.addIntArg(contourFinder.nBlobs);
        //sender.sendMessage(numContours);

        for (int i = 0; i < contourFinder.nBlobs; i++){

            ofxOscMessage message;
            stringstream messageAddress;
            float x = contourFinder.blobs[i].boundingRect.x;
            float y = contourFinder.blobs[i].boundingRect.y;
            float width = contourFinder.blobs[i].boundingRect.width;
            float height = contourFinder.blobs[i].boundingRect.height;

            //normalization
            x = x / 160;
            y = y / 120;
            width = width / 160;
            height = height / 120;

            //openGl standard
            x = x + width/2;
            y = y + height /2;
            x = x * 2 - 1;
            y = y * -2 + 1;
            width*=2;
            height*=2;

            if ( y - height/2 < 0 ) {
		message.addFloatArg(x);
                message.addFloatArg(y);
                message.addFloatArg(width);
                message.addFloatArg(height);

		messageAddress << "/RPi_" << RPiId << "/contour_" << (i + 1) << "/";
		message.setAddress(messageAddress.str());
                sender.sendMessage(message);
                sent_blobs++;
            }

        }

        numContours.addIntArg(sent_blobs);
		sender.sendMessage(numContours);

    }

	// check for waiting messages
	while(receiver.hasWaitingMessages()){
		// get the next message
		ofxOscMessage rm;//receivedMessage
		ofxOscMessage sm;//sentMessage
		receiver.getNextMessage(&rm);
                //probably we need to move it out of the update
		if(rm.getAddress() == "/save"){
			gui.saveToFile(filename_save);
		}
		if(rm.getAddress() == "/getParams"){
			sm.setAddress("/allParams");
			sm.addStringArg(RPiId);
			sm.addIntArg(cutDown);
			sm.addIntArg(fps);
			sm.addIntArg(learningTime);
			sm.addIntArg(backgroundThreshold);
			sm.addIntArg(erodeFactor);
			sm.addIntArg(dilateFactor);
			sm.addIntArg(medianBlurFactor);
			sm.addIntArg(minContourArea);
			sm.addIntArg(maxContourArea);
			sm.addIntArg(maxContours);

			sender.sendMessage(sm);
		}
		else if(rm.getAddress() == "/whoIsThere"){
			sm.setAddress("/RPiId");
			sm.addStringArg(RPiId);
			sender.sendMessage(sm);
		}
		else if(rm.getAddress() == "/cutDown" + RPiId){
			cutDown = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/fps" + RPiId){
			fps = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/learningTime" + RPiId){
			learningTime = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/backgroundThreshold" + RPiId){
			backgroundThreshold = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/erodeFactor" + RPiId){
			erodeFactor = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/dilateFactor" + RPiId){
			dilateFactor = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/medianBlurFactor" + RPiId){
			medianBlurFactor = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/minContourArea" + RPiId){
			minContourArea = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/maxContourArea" + RPiId){
			maxContourArea = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/maxContours" + RPiId){
			maxContours = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/maxContours" + RPiId){
			maxContours = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/roiX" + RPiId){
			roiX = rm.getArgAsFloat(0);
		}
		else if(rm.getAddress() == "/roiY" + RPiId){
			roiY = rm.getArgAsFloat(0);
		}
		else if(rm.getAddress() == "/roiW" + RPiId){
			roiW = rm.getArgAsFloat(0);
		}
		else if(rm.getAddress() == "/roiH" + RPiId){
			roiH = rm.getArgAsFloat(0);
		}
		else if(rm.getAddress() == "/exposureCompensation" + RPiId){
			exposureCompensation = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/exposureMeteringMode" + RPiId){
			exposureMeteringMode = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/exposureMode" + RPiId){
			exposureMode = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/awbMode" + RPiId){
			awbMode = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/shutterSpeed" + RPiId){
			shutterSpeed = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/resetBG" + RPiId){
			background.reset();
		}
		else if(rm.getAddress() == "/loadFromFile" + RPiId){
			if(ofFile::doesFileExist(filename_save)){
				ofLog(OF_LOG_NOTICE) << "loading from file " + filename_save << endl;
				gui.loadFromFile(filename_save);
			}
			else{
				ofLog(OF_LOG_NOTICE) << "file " + filename_save + " does not exist" << endl;
			}
		}

	}
}

//-- Parameters events listeners

void ofApp::fpsChanged(int &fps) {
    ofSetFrameRate(fps);
}

void ofApp::learningTimeChanged(int &learningTime) {
    background.setLearningTime(learningTime);
}

void ofApp::backgroundThresholdChanged(int &backgroundThreshold) {
    background.setThresholdValue(backgroundThreshold);
}

//--------------------------------------------------------------
void ofApp::draw(){
//#ifdef __arm__
    drawMat(frame,0,0,320,240);
    drawMat(frameProcessed,0,240,320,240);
    thresholded.draw(320, 0,320,240);

    contourFinder.draw(320,240,320,240);

    gui.draw();
//#endif
}

//--------------------------------------------------------------
void ofApp::keyPressed  (int key){
    ofLogVerbose() << "keyPressed: " << key;

    if(key == ' ') {
        background.reset();
    }

    if(key == 'r') {
        framenr = 1;
        ofLog()<< "restarting video";
    }
	if(key == 's') {
		gui.saveToFile(filename_save);
		ofLog()<< "saved "+filename_save;
	}
	if(key == 'l') {
		gui.loadFromFile(filename_save);
		ofLog()<< "loaded "+filename_save;
	}
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
    //thresh = ofMap(x,0,ofGetWidth(),0,255);
}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

#ifdef __arm__
void ofApp::roiXChanged(float &roiX){
    ROI.x = roiX;
    cam.setROI(ROI);
}
void ofApp::roiYChanged(float &roiY){
    ROI.y = roiY;
    cam.setROI(ROI);
}
void ofApp::roiWChanged(float &roiW){
    ROI.width = roiW;
    cam.setROI(ROI);
}
void ofApp::roiHChanged(float &roiH){
    ROI.height = roiH;
    cam.setROI(ROI);
}
void ofApp::exposureCompensationChanged(int &exposureCompensation){
    cam.setExposureCompensation(exposureCompensation);
}
void ofApp::exposureMeteringModeChanged(int &exposureMeteringMode){
    //exposureMeteringMode.setName(exposureMeteringModes[exposureMeteringModeValue]);                            //display the preset name in the UI
    if(exposureMeteringModeValue == exposureMeteringMode.getMax()) exposureMeteringModeValue = MMAL_PARAM_EXPOSUREMETERINGMODE_MAX;//the preset max value is different from the UI
    cam.setExposureMeteringMode((MMAL_PARAM_EXPOSUREMETERINGMODE_T)exposureMeteringModeValue);
}
void ofApp::exposureModeChanged(int &exposureMode){
    //exposureMode.setName(exposureModes[exposureMode]);//display the preset name in the UI
    if(exposureMode == exposureMode.getMax()) exposureMode = MMAL_PARAM_EXPOSUREMODE_MAX;//the preset max value is different from the UI
    cam.setExposureMode((MMAL_PARAM_EXPOSUREMODE_T)exposureMode);
}
void ofApp::awbModeChanged(int &awbMode){
    //awbMode.setName(awbModes[awbModeValue]);//display the preset name in the UI
    if(awbMode == awbMode.getMax()) awbMode = MMAL_PARAM_AWBMODE_MAX;//the preset max value is different from the UI
    cam.setAWBMode((MMAL_PARAM_AWBMODE_T)awbMode);
}
void ofApp::shutterSpeedChanged(int &shutterSpeed){
    cam.setShutterSpeed(shutterSpeed);
}
#endif
<commit_msg>array value update<commit_after>#include "ofApp.h"
#include <opencv2/opencv.hpp>

using namespace ofxCv;
using namespace cv;

void ofApp::onCharacterReceived(SSHKeyListenerEventData& e)
{
	keyPressed((int)e.character);
}
//--------------------------------------------------------------
void ofApp::setup(){

    ofLog() << "RPid " << RPiId;
    gui.setup("panel");
    gui.setPosition(650,10);
    gui.add(cutDown.set( "cutDown", 110, 1, 255 ));
    gui.add(fps.set("fps", 15, 1, 30));
    gui.add(learningTime.set("learningTime",100,1,1000));
    gui.add(backgroundThreshold.set("backgroundThreshold",20,1,300));
    gui.add(erodeFactor.set("erodeFactor",0,0,3));
    gui.add(dilateFactor.set("dilateFactor",2,0,3));
    gui.add(medianBlurFactor.set("medianBlur",3,0,5));
    gui.add(minContourArea.set("minContourArea",20, 5, 40));
    gui.add(maxContourArea.set("maxContourArea", 300, 40, 160*120)); // one third of the screen.
    gui.add(maxContours.set("maxContours", 5, 1, 10));
    ofSetFrameRate(fps);
    //experimenting
    gui.add(exposureCompensation.set("exposure compensation",0,-10,10));
    gui.add(exposureMeteringMode.set("exposure metering mode",0,0,4));
    gui.add(exposureMode.set("exposure mode",0,0,13));
    gui.add(shutterSpeed.set("shutter speed",0,0,330000));//(in micro seconds)
    gui.add(awbMode.set("AutoWhiteBalance mode",0,0,10));
    gui.add(roiX.set("ROI x",0,0,1));
    gui.add(roiY.set("ROI y",0,0,1));
    gui.add(roiW.set("ROI w",1,0,1));
    gui.add(roiH.set("ROI h",1,0,1));
    //experimenting off
    filename_save = "RPi_" + RPiId + "_settings.xml";

    if(ofFile::doesFileExist(filename_save)){
        ofLog(OF_LOG_NOTICE)<< "loading from file" + filename_save << endl;
        gui.loadFromFile(filename_save);
    }

    consoleListener.setup(this);
    consoleListener.startThread(false, false);

    background.setLearningTime(learningTime);
    background.setThresholdValue(backgroundThreshold);

	// if we set setIgnoreForeground to true
	// we will have problems in case of rain.
//	background.setIgnoreForeground(true);

    fps.addListener(this, &ofApp::fpsChanged);
    learningTime.addListener(this, &ofApp::learningTimeChanged);
    backgroundThreshold.addListener(this, &ofApp::backgroundThresholdChanged);

    exposureMeteringModes[0] = "average";
	exposureMeteringModes[1] = "spot";
	exposureMeteringModes[2] = "backlit";
	exposureMeteringModes[3] = "matrix";
	exposureMeteringModes[4] = "max";

	exposureModes[ 0] = "off";
	exposureModes[ 1] = "auto";
	exposureModes[ 2] = "night";
	exposureModes[ 3] = "night preview";
	exposureModes[ 4] = "backlight";
	exposureModes[ 5] = "spotlight";
	exposureModes[ 6] = "sports";
	exposureModes[ 7] = "snow";
	exposureModes[ 8] = "beach";
	exposureModes[ 9] = "very long";
	exposureModes[10] = "fixed fps";
	exposureModes[11] = "antishake";
	exposureModes[12] = "fireworks";
	exposureModes[13] = "max";

#ifdef __arm__
    cam.setup(160,120,false);//setup camera (w,h,color = true,gray = false);
    cam.setExposureMode(MMAL_PARAM_EXPOSUREMODE_FIXEDFPS);

	// one of these two gives black during night time
//    cam.setExposureCompensation(0);
//    cam.setAWBMode(MMAL_PARAM_AWBMODE_OFF);

#else
    cam.initGrabber(160,120);
#endif

    //sender.setup("192.168.255.255", 8000);
    sender.setup("192.168.1.3", 8000);
 	receiver.setup(OSC_PORT);
}

static int framenr = 1;

//--------------------------------------------------------------
void ofApp::update(){
    sent_blobs = 0;
	framenr++;

	// IF running from RPi
#ifdef __arm__
    frame = Mat(cam.grab());
    stringstream ss;
    ss << "rpi_" << RPiId << ".png";
    if(framenr % 100 == 0) {
      toOf(frame,tosave);

      ofSaveImage(tosave, ss.str());
    }

	// IF running from Computer
#else
    string filename;
    filename = "images/file" + ofToString(framenr) + ".png";
    image.loadImage(filename);
    image.rotate90(2);
	image.setImageType(OF_IMAGE_COLOR);
    frame = toCv(image);
#endif

    if (framenr == 130) {
        background.reset();
    }

    if (!frame.empty()) {

        threshold( frame, frame, cutDown, 255, 2 );

        background.update(frame, thresholded);
        thresholded.update();

        frameProcessed = toCv(thresholded);
        medianBlur ( frameProcessed, frameProcessed, medianBlurFactor );
        erode( frameProcessed, frameProcessed, erodeFactor );
        dilate( frameProcessed, frameProcessed, dilateFactor );

        toOf(frameProcessed, pix);
        grayImage.setFromPixels(pix);

        contourFinder.findContours(grayImage, minContourArea, maxContourArea, maxContours, true); // find holes

        ofxOscMessage numContours;
        stringstream addr;
        addr << "/RPi_" << RPiId << "/total_contours/";
        numContours.setAddress(addr.str());
        //numContours.addIntArg(contourFinder.nBlobs);
        //sender.sendMessage(numContours);

        for (int i = 0; i < contourFinder.nBlobs; i++){

            ofxOscMessage message;
            stringstream messageAddress;
            float x = contourFinder.blobs[i].boundingRect.x;
            float y = contourFinder.blobs[i].boundingRect.y;
            float width = contourFinder.blobs[i].boundingRect.width;
            float height = contourFinder.blobs[i].boundingRect.height;

            //normalization
            x = x / 160;
            y = y / 120;
            width = width / 160;
            height = height / 120;

            //openGl standard
            x = x + width/2;
            y = y + height /2;
            x = x * 2 - 1;
            y = y * -2 + 1;
            width*=2;
            height*=2;

            if ( y - height/2 < 0 ) {
		message.addFloatArg(x);
                message.addFloatArg(y);
                message.addFloatArg(width);
                message.addFloatArg(height);

		messageAddress << "/RPi_" << RPiId << "/contour_" << (i + 1) << "/";
		message.setAddress(messageAddress.str());
                sender.sendMessage(message);
                sent_blobs++;
            }

        }

        numContours.addIntArg(sent_blobs);
		sender.sendMessage(numContours);

    }

	// check for waiting messages
	while(receiver.hasWaitingMessages()){
		// get the next message
		ofxOscMessage rm;//receivedMessage
		ofxOscMessage sm;//sentMessage
		receiver.getNextMessage(&rm);
                //probably we need to move it out of the update
		if(rm.getAddress() == "/save"){
			gui.saveToFile(filename_save);
		}
		if(rm.getAddress() == "/getParams"){
			sm.setAddress("/allParams");
			sm.addStringArg(RPiId);
			sm.addIntArg(cutDown);
			sm.addIntArg(fps);
			sm.addIntArg(learningTime);
			sm.addIntArg(backgroundThreshold);
			sm.addIntArg(erodeFactor);
			sm.addIntArg(dilateFactor);
			sm.addIntArg(medianBlurFactor);
			sm.addIntArg(minContourArea);
			sm.addIntArg(maxContourArea);
			sm.addIntArg(maxContours);

			sender.sendMessage(sm);
		}
		else if(rm.getAddress() == "/whoIsThere"){
			sm.setAddress("/RPiId");
			sm.addStringArg(RPiId);
			sender.sendMessage(sm);
		}
		else if(rm.getAddress() == "/cutDown" + RPiId){
			cutDown = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/fps" + RPiId){
			fps = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/learningTime" + RPiId){
			learningTime = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/backgroundThreshold" + RPiId){
			backgroundThreshold = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/erodeFactor" + RPiId){
			erodeFactor = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/dilateFactor" + RPiId){
			dilateFactor = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/medianBlurFactor" + RPiId){
			medianBlurFactor = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/minContourArea" + RPiId){
			minContourArea = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/maxContourArea" + RPiId){
			maxContourArea = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/maxContours" + RPiId){
			maxContours = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/maxContours" + RPiId){
			maxContours = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/roiX" + RPiId){
			roiX = rm.getArgAsFloat(0);
		}
		else if(rm.getAddress() == "/roiY" + RPiId){
			roiY = rm.getArgAsFloat(0);
		}
		else if(rm.getAddress() == "/roiW" + RPiId){
			roiW = rm.getArgAsFloat(0);
		}
		else if(rm.getAddress() == "/roiH" + RPiId){
			roiH = rm.getArgAsFloat(0);
		}
		else if(rm.getAddress() == "/exposureCompensation" + RPiId){
			exposureCompensation = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/exposureMeteringMode" + RPiId){
			exposureMeteringMode = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/exposureMode" + RPiId){
			exposureMode = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/awbMode" + RPiId){
			awbMode = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/shutterSpeed" + RPiId){
			shutterSpeed = rm.getArgAsInt32(0);
		}
		else if(rm.getAddress() == "/resetBG" + RPiId){
			background.reset();
		}
		else if(rm.getAddress() == "/loadFromFile" + RPiId){
			if(ofFile::doesFileExist(filename_save)){
				ofLog(OF_LOG_NOTICE) << "loading from file " + filename_save << endl;
				gui.loadFromFile(filename_save);
			}
			else{
				ofLog(OF_LOG_NOTICE) << "file " + filename_save + " does not exist" << endl;
			}
		}

	}
}

//-- Parameters events listeners

void ofApp::fpsChanged(int &fps) {
    ofSetFrameRate(fps);
}

void ofApp::learningTimeChanged(int &learningTime) {
    background.setLearningTime(learningTime);
}

void ofApp::backgroundThresholdChanged(int &backgroundThreshold) {
    background.setThresholdValue(backgroundThreshold);
}

//--------------------------------------------------------------
void ofApp::draw(){
//#ifdef __arm__
    drawMat(frame,0,0,320,240);
    drawMat(frameProcessed,0,240,320,240);
    thresholded.draw(320, 0,320,240);

    contourFinder.draw(320,240,320,240);

    gui.draw();
//#endif
}

//--------------------------------------------------------------
void ofApp::keyPressed  (int key){
    ofLogVerbose() << "keyPressed: " << key;

    if(key == ' ') {
        background.reset();
    }

    if(key == 'r') {
        framenr = 1;
        ofLog()<< "restarting video";
    }
	if(key == 's') {
		gui.saveToFile(filename_save);
		ofLog()<< "saved "+filename_save;
	}
	if(key == 'l') {
		gui.loadFromFile(filename_save);
		ofLog()<< "loaded "+filename_save;
	}
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
    //thresh = ofMap(x,0,ofGetWidth(),0,255);
}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

#ifdef __arm__
void ofApp::roiXChanged(float &roiX){
    ROI.x = roiX;
    cam.setROI(ROI);
}
void ofApp::roiYChanged(float &roiY){
    ROI.y = roiY;
    cam.setROI(ROI);
}
void ofApp::roiWChanged(float &roiW){
    ROI.width = roiW;
    cam.setROI(ROI);
}
void ofApp::roiHChanged(float &roiH){
    ROI.height = roiH;
    cam.setROI(ROI);
}
void ofApp::exposureCompensationChanged(int &exposureCompensation){
    cam.setExposureCompensation(exposureCompensation);
}
void ofApp::exposureMeteringModeChanged(int &exposureMeteringMode){
    //exposureMeteringMode.setName(exposureMeteringModes[exposureMeteringModeValue]);                            //display the preset name in the UI
    if(exposureMeteringMode == exposureMeteringMode.getMax()) exposureMeteringMode = MMAL_PARAM_EXPOSUREMETERINGMODE_MAX;//the preset max value is different from the UI
    cam.setExposureMeteringMode((MMAL_PARAM_EXPOSUREMETERINGMODE_T)exposureMeteringMode);
}
void ofApp::exposureModeChanged(int &exposureMode){
    //exposureMode.setName(exposureModes[exposureMode]);//display the preset name in the UI
    if(exposureMode == exposureMode.getMax()) exposureMode = MMAL_PARAM_EXPOSUREMODE_MAX;//the preset max value is different from the UI
    cam.setExposureMode((MMAL_PARAM_EXPOSUREMODE_T)exposureMode);
}
void ofApp::awbModeChanged(int &awbMode){
    //awbMode.setName(awbModes[awbModeValue]);//display the preset name in the UI
    if(awbMode == awbMode.getMax()) awbMode = MMAL_PARAM_AWBMODE_MAX;//the preset max value is different from the UI
    cam.setAWBMode((MMAL_PARAM_AWBMODE_T)awbMode);
}
void ofApp::shutterSpeedChanged(int &shutterSpeed){
    cam.setShutterSpeed(shutterSpeed);
}
#endif
<|endoftext|>


<commit_before>#include <sstream>
#include <iostream>
#include "Shell.h"
#include "DiffCommand.h"
#include <Node.h>
#include <NodePool.h>

namespace RhIO
{
    std::string DiffCommand::getName()
    {
        return "diff";
    }

    std::string DiffCommand::getDesc()
    {
        return "Shows the diff";
    }

    void DiffCommand::process(std::vector<std::string> args)
    {
        auto node = getNode(args);

        if (!showDiff(node)) {
            Terminal::setColor("green", true);
            std::cout << "Everything is clean" << std::endl;
            Terminal::clear();
        }
    }

    int DiffCommand::showDiff(Node *node)
    {
        int diff = 0;

        for (auto nodeVal : node->getAll()) {
            auto value = nodeVal.value;
            if (value->persisted && Node::isDiff(value)) {
                diff++;
                std::cout << "/" << nodeVal.getName();
                std::cout << ": ";
                Terminal::setColor("red", true);
                std::cout << Node::persistedToString(value);
                Terminal::setColor("white", false);
                std::cout << " -> ";
                Terminal::setColor("green", true);
                std::cout << Node::toString(value);
                std::cout << std::endl;
            }
        }

        for (auto entry : node->children) {
            diff += showDiff(entry.second);
        }
        return diff;
    }
}
<commit_msg>Changing style of diff command<commit_after>#include <sstream>
#include <iostream>
#include "Shell.h"
#include "DiffCommand.h"
#include <Node.h>
#include <NodePool.h>

namespace RhIO
{
    std::string DiffCommand::getName()
    {
        return "diff";
    }

    std::string DiffCommand::getDesc()
    {
        return "Shows the diff";
    }

    void DiffCommand::process(std::vector<std::string> args)
    {
        auto node = getNode(args);

        if (!showDiff(node)) {
            Terminal::setColor("green", true);
            std::cout << "Everything is clean" << std::endl;
            Terminal::clear();
        }
    }

    int DiffCommand::showDiff(Node *node)
    {
        int diff = 0;

        for (auto nodeVal : node->getAll()) {
            auto value = nodeVal.value;
            if (value->persisted && Node::isDiff(value)) {
                Terminal::clear();
                diff++;
                std::string name = std::string("/") + nodeVal.getName() + ":";
                printf("%-20s ", name.c_str());

                Terminal::setColor("red", true);
                printf("%-5s", Node::persistedToString(value).c_str());
                Terminal::setColor("white", false);
                std::cout << " → ";
                Terminal::setColor("green", true);
                printf("%-5s", Node::toString(value).c_str());

                std::cout << std::endl;
            }
        }

        for (auto entry : node->children) {
            diff += showDiff(entry.second);
        }
        return diff;
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "core/Setup.h"
#include <iostream>
#include <string>

#if OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
#include <sys/syslog.h>
#endif

#if OUZEL_PLATFORM_WINDOWS
#include <windows.h>
#include <strsafe.h>
#endif

#if OUZEL_PLATFORM_ANDROID
#include <android/log.h>
#endif

#if OUZEL_PLATFORM_EMSCRIPTEN
#include <emscripten.h>
#endif

#include "Log.hpp"

namespace ouzel
{
#ifdef DEBUG
    Log::Level Log::threshold = Log::Level::ALL;
#else
    Log::Level Log::threshold = Log::Level::INFO;

#endif

    Log::~Log()
    {
        if (!s.empty())
        {
#if OUZEL_PLATFORM_MACOS || OUZEL_PLATFORM_LINUX || OUZEL_PLATFORM_RASPBIAN
            switch (level)
            {
                case Level::ERR:
                case Level::WARN:
                    std::cerr << s << std::endl;
                    break;
                case Level::INFO:
                case Level::ALL:
                    std::cout << s << std::endl;
                    break;
                default: break;
            }
#elif OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
            int priority = 0;
            switch (level)
            {
                case Level::ERR: priority = LOG_ERR; break;
                case Level::WARN: priority = LOG_WARNING; break;
                case Level::INFO: priority = LOG_INFO; break;
                case Level::ALL: priority = LOG_DEBUG; break;
                default: break;
            }
            syslog(priority, "%s", s.c_str());
#elif OUZEL_PLATFORM_WINDOWS
            std::vector<wchar_t> szBuffer(s.length() + 2);
            if (MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, szBuffer.data(), static_cast<int>(szBuffer.size())) == 0)
            {
                Log(Log::Level::ERR) << "Failed to convert UTF-8 to wide char";
                return;
            }

            StringCchCatW(szBuffer.data(), szBuffer.size(), L"\n");
            OutputDebugStringW(szBuffer.data());

    #if DEBUG
            HANDLE handle = 0;
            switch (level)
            {
            case Level::ERR:
            case Level::WARN:
                handle = GetStdHandle(STD_ERROR_HANDLE);
                break;
            case Level::INFO:
            case Level::ALL:
                handle = GetStdHandle(STD_OUTPUT_HANDLE);
                break;
            default: break;
            }

            if (handle)
            {
                DWORD bytesWritten;
                WriteConsoleW(handle, szBuffer.data(), static_cast<DWORD>(wcslen(szBuffer.data())), &bytesWritten, nullptr);
            }
    #endif

#elif OUZEL_PLATFORM_ANDROID
            int priority = 0;
            switch (level)
            {
                case Level::ERR: priority = ANDROID_LOG_ERROR; break;
                case Level::WARN: priority = ANDROID_LOG_WARN; break;
                case Level::INFO: priority = ANDROID_LOG_INFO; break;
                case Level::ALL: priority = ANDROID_LOG_DEBUG; break;
                default: break;
            }
            __android_log_print(priority, "Ouzel", "%s", s.c_str());
#elif OUZEL_PLATFORM_EMSCRIPTEN
            int flags = EM_LOG_CONSOLE;
            if (level == Level::ERR) flags |= EM_LOG_ERROR;
            else if (level == Level::WARN) flags |= EM_LOG_WARN;
            emscripten_log(flags, "%s", s.c_str());
#endif
            s.clear();
        }
    }
}
<commit_msg>Add one char to szBuffer instead of two<commit_after>// Copyright (C) 2018 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "core/Setup.h"
#include <iostream>
#include <string>

#if OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
#include <sys/syslog.h>
#endif

#if OUZEL_PLATFORM_WINDOWS
#include <windows.h>
#include <strsafe.h>
#endif

#if OUZEL_PLATFORM_ANDROID
#include <android/log.h>
#endif

#if OUZEL_PLATFORM_EMSCRIPTEN
#include <emscripten.h>
#endif

#include "Log.hpp"

namespace ouzel
{
#ifdef DEBUG
    Log::Level Log::threshold = Log::Level::ALL;
#else
    Log::Level Log::threshold = Log::Level::INFO;

#endif

    Log::~Log()
    {
        if (!s.empty())
        {
#if OUZEL_PLATFORM_MACOS || OUZEL_PLATFORM_LINUX || OUZEL_PLATFORM_RASPBIAN
            switch (level)
            {
                case Level::ERR:
                case Level::WARN:
                    std::cerr << s << std::endl;
                    break;
                case Level::INFO:
                case Level::ALL:
                    std::cout << s << std::endl;
                    break;
                default: break;
            }
#elif OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
            int priority = 0;
            switch (level)
            {
                case Level::ERR: priority = LOG_ERR; break;
                case Level::WARN: priority = LOG_WARNING; break;
                case Level::INFO: priority = LOG_INFO; break;
                case Level::ALL: priority = LOG_DEBUG; break;
                default: break;
            }
            syslog(priority, "%s", s.c_str());
#elif OUZEL_PLATFORM_WINDOWS
            std::vector<wchar_t> szBuffer(s.length() + 1);
            if (MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, szBuffer.data(), static_cast<int>(szBuffer.size())) == 0)
            {
                Log(Log::Level::ERR) << "Failed to convert UTF-8 to wide char";
                return;
            }

            StringCchCatW(szBuffer.data(), szBuffer.size(), L"\n");
            OutputDebugStringW(szBuffer.data());

    #if DEBUG
            HANDLE handle = 0;
            switch (level)
            {
            case Level::ERR:
            case Level::WARN:
                handle = GetStdHandle(STD_ERROR_HANDLE);
                break;
            case Level::INFO:
            case Level::ALL:
                handle = GetStdHandle(STD_OUTPUT_HANDLE);
                break;
            default: break;
            }

            if (handle)
            {
                DWORD bytesWritten;
                WriteConsoleW(handle, szBuffer.data(), static_cast<DWORD>(wcslen(szBuffer.data())), &bytesWritten, nullptr);
            }
    #endif

#elif OUZEL_PLATFORM_ANDROID
            int priority = 0;
            switch (level)
            {
                case Level::ERR: priority = ANDROID_LOG_ERROR; break;
                case Level::WARN: priority = ANDROID_LOG_WARN; break;
                case Level::INFO: priority = ANDROID_LOG_INFO; break;
                case Level::ALL: priority = ANDROID_LOG_DEBUG; break;
                default: break;
            }
            __android_log_print(priority, "Ouzel", "%s", s.c_str());
#elif OUZEL_PLATFORM_EMSCRIPTEN
            int flags = EM_LOG_CONSOLE;
            if (level == Level::ERR) flags |= EM_LOG_ERROR;
            else if (level == Level::WARN) flags |= EM_LOG_WARN;
            emscripten_log(flags, "%s", s.c_str());
#endif
            s.clear();
        }
    }
}
<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: SteepestDescentMinimizer_test.C,v 1.4 2003/04/12 10:06:06 oliver Exp $
#include <BALL/CONCEPT/classTest.h>

///////////////////////////
#include <BALL/MOLMEC/MINIMIZATION/steepestDescent.h>
#include <BALL/MOLMEC/AMBER/amber.h>
#include <BALL/DATATYPE/options.h>
#include <BALL/KERNEL/PTE.h>
#include <BALL/FORMAT/HINFile.h>
#include <BALL/MATHS/analyticalGeometry.h>

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

START_TEST(ConjugateGradienMinimizer, "$Id: SteepestDescentMinimizer_test.C,v 1.4 2003/04/12 10:06:06 oliver Exp $")

using namespace BALL;

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

System S;
AmberFF FF(S);

SteepestDescentMinimizer*	em;
CHECK(SteepestDescentMinimizer::SteepestDescentMinimizer())
	em = new SteepestDescentMinimizer;
	TEST_NOT_EQUAL(em, 0)
RESULT

CHECK(SteepestDescentMinimizer::~SteepestDescentMinimizer())
	delete em;
RESULT

CHECK(SteepestDescentMinimizer::getForceField())
	SteepestDescentMinimizer em;
	TEST_EQUAL(em.getForceField(), 0)
RESULT

CHECK(SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField&))
	TEST_EQUAL(FF.isValid(), true)
	SteepestDescentMinimizer em(FF);
	TEST_EQUAL(em.getForceField(), &FF)
RESULT

CHECK(SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField&, const Options&))
	Options options;
	options.set("ABC", "DEF");
	em = new SteepestDescentMinimizer(FF, options);
	TEST_EQUAL(em->getForceField(), &FF)
	TEST_EQUAL(em->options["ABC"], "DEF")
	delete em;
RESULT

CHECK(SteepestDescentMinimizer::SteepestDescentMinimizer(const SteepestDescentMinimizer&, bool))
	SteepestDescentMinimizer em1;
	SteepestDescentMinimizer em2(em1);
	bool test = (em1 == em2);
	TEST_EQUAL(test, true)
	em1.setup(FF);
	SteepestDescentMinimizer em3(em1);
	test = (em1 == em3);
	TEST_EQUAL(test, true)
	em1.setup(FF);
RESULT

CHECK(SteepestDescentMinimizer::operator = (const SteepestDescentMinimizer&))
	SteepestDescentMinimizer em1;
	SteepestDescentMinimizer em2 = em1;
	bool test = (em1 == em2);
	TEST_EQUAL(test, true)
	em1.setup(FF);
	SteepestDescentMinimizer em3 = em1;
	test = (em1 == em3);
	TEST_EQUAL(test, true)
RESULT

CHECK(SteepestDescentMinimizer::isValid() const)
	em = new SteepestDescentMinimizer;
	TEST_EQUAL(em->isValid(), false)
	delete em;
	em = new SteepestDescentMinimizer(FF);
	TEST_EQUAL(em->isValid(), true)
	delete em;
RESULT

CHECK(SteepestDescentMinimizer::setup(ForceField&))
	SteepestDescentMinimizer e_min(FF);
	TEST_EQUAL(e_min.getForceUpdateCounter(), 0)
	TEST_EQUAL(e_min.getEnergyUpdateCounter(), 0)
	bool test = (e_min.getForceField() == &FF);
	TEST_EQUAL(test, true)
RESULT

CHECK(SteepestDescentMinimizer::setup(ForceField&, const Options&))
	Options options;
	options.setInteger(EnergyMinimizer::Option::ENERGY_OUTPUT_FREQUENCY, 3456);
	SteepestDescentMinimizer e_min(FF, options);
	TEST_EQUAL(e_min.getForceUpdateCounter(), 0)
	TEST_EQUAL(e_min.getEnergyUpdateCounter(), 0)
	bool test = (e_min.getForceField() == &FF);
	TEST_EQUAL(test, true)
	TEST_EQUAL(e_min.getEnergyOutputFrequency(), 3456)
RESULT

CHECK(SteepestDescentMinimizer::specificSetup())
	SteepestDescentMinimizer em(FF);
	TEST_EQUAL(em.specificSetup(), true)
	// specificSetup() shouldn't do anything except returning true
RESULT

CHECK(SteepestDescentMinimizer::getNumberOfIteration() const)
	SteepestDescentMinimizer e_min;
	TEST_EQUAL(e_min.getNumberOfIterations(), 0)
RESULT

CHECK(SteepestDescentMinimizer::setNumberOfIteration(Size))
	SteepestDescentMinimizer e_min;
	e_min.setNumberOfIterations(4);
	TEST_EQUAL(e_min.getNumberOfIterations(), 4)
RESULT

CHECK(SteepestDescentMinimizer::getMaxNumberOfIterations())
	SteepestDescentMinimizer e_min;
	TEST_EQUAL(e_min.getMaxNumberOfIterations(), 0)
RESULT

CHECK(SteepestDescentMinimizer::setMaxNumberOfIterations(Size))
	SteepestDescentMinimizer e_min;
	e_min.setMaxNumberOfIterations(2000);
	TEST_EQUAL(e_min.getMaxNumberOfIterations(), 2000)
RESULT

CHECK(SteepestDescentMinimizer::getEnergyOutputFrequency() const)
	SteepestDescentMinimizer e_min2;
	TEST_EQUAL(e_min2.getEnergyOutputFrequency(), 0)
RESULT

CHECK(SteepestDescentMinimizer::setEnergyOutputFrequency(Size))
	SteepestDescentMinimizer e_min;
	e_min.setEnergyOutputFrequency(8);
	TEST_EQUAL(e_min.getEnergyOutputFrequency(), 8)
RESULT

CHECK(SteepestDescentMinimizer::getEnergyDifferenceBound() const)
	SteepestDescentMinimizer e_min;
	TEST_EQUAL(e_min.getEnergyDifferenceBound(), 0.0)
RESULT

CHECK(SteepestDescentMinimizer::setEnergyDifferenceBound(float))
	SteepestDescentMinimizer e_min;
	e_min.setEnergyDifferenceBound(9.0);
	TEST_EQUAL(e_min.getEnergyDifferenceBound(), 9.0)
RESULT

CHECK(SteepestDescentMinimizer::getMaximumDisplacement() const)
	SteepestDescentMinimizer e_min;
	TEST_EQUAL(e_min.getMaximumDisplacement(), 0.0)
RESULT

CHECK(SteepestDescentMinimizer::setMaximumDisplacement(float))
	SteepestDescentMinimizer e_min;
	e_min.setMaximumDisplacement(56.0);
	TEST_EQUAL(e_min.getMaximumDisplacement(), 56.0)
RESULT

CHECK(SteepestDescentMinimizer::minimize(Size, bool))
	System S;
	Molecule* m = new Molecule;
	Atom* a1 = new Atom;
	Atom* a2 = new Atom;
	S.insert(*m);
	m->insert(*a1);
	m->insert(*a2);
	a1->setPosition(Vector3(-0.5, 0, 0));
	a2->setPosition(Vector3(0.5, 0, 0));
	a1->setElement(PTE[Element::C]);
	a2->setElement(PTE[Element::C]);
	a1->setTypeName("C");
	a2->setTypeName("C");
	a1->setCharge(0.0);
	a2->setCharge(0.0);
	FF.options[AmberFF::Option::ASSIGN_CHARGES] = "false";
	FF.setup(S);
	TEST_EQUAL(FF.isValid(), true)
	PRECISION(1e-4)
	FF.updateEnergy();
	FF.updateForces();
	PRECISION(10)
	TEST_REAL_EQUAL(FF.getEnergy(), 3.42854e+06)
	SteepestDescentMinimizer cgm(FF);
	cgm.setEnergyOutputFrequency(1);
	cgm.setMaxGradient(0.01);
	TEST_EQUAL(cgm.isValid(), true)
	TEST_EQUAL(cgm.minimize(20), true)

	FF.updateEnergy();
	FF.updateForces();

	PRECISION(1e-3)
  TEST_REAL_EQUAL(FF.getEnergy(), -0.359813)
	PRECISION(7e-3)
  TEST_REAL_EQUAL(a1->getPosition().getDistance(a2->getPosition()), 3.81244)
RESULT

CHECK(SteepestDescentMinimizer::minimize(Size, bool) ethan)
  System S;
  HINFile f("data/ethan.hin");
  f >> S;
  FF.options[AmberFF::Option::ASSIGN_CHARGES] = "false";
  FF.setup(S);

  TEST_EQUAL(FF.isValid(), true)
  FF.updateEnergy();
  FF.updateForces();
  PRECISION(1E-4)
  TEST_REAL_EQUAL(FF.getEnergy(), 18.5605)

  SteepestDescentMinimizer sd(FF);

  sd.setEnergyOutputFrequency(5);
  sd.setMaxGradient(0.418);
	sd.setMaxNumberOfIterations(10000);
  sd.setEnergyDifferenceBound(0.00000001);

  TEST_EQUAL(sd.isValid(), true)
  FF.updateEnergy();
  FF.updateForces();
  bool result = sd.minimize(500);

  TEST_EQUAL(result, true)
  float energy = FF.updateEnergy();
  FF.updateForces();

  PRECISION(6E-2)
  TEST_REAL_EQUAL(energy, 5.906)

  AtomIterator atit;
  Vector3 pos[8];
  int i=0;

  for (atit = S.beginAtom(); +atit; ++atit)
  {
    pos[i] = atit->getPosition();
    ++i;
	}

  PRECISION(5E-2)
  Angle torsion;
  torsion = getTorsionAngle(pos[2].x, pos[2].y, pos[2].z, pos[0].x, pos[0].y, pos[0].z, pos[1].x, pos[1].y, pos[1].z, pos[6].x, pos[6].y, pos[6].z);
  TEST_REAL_EQUAL(torsion.toRadian(), 1.047)
  torsion = getTorsionAngle(pos[3].x, pos[3].y, pos[3].z, pos[0].x, pos[0].y, pos[0].z, pos[1].x, pos[1].y, pos[1].z, pos[5].x, pos[5].y, pos[5].z);
  TEST_REAL_EQUAL(torsion.toRadian(), 1.047)
  torsion = getTorsionAngle(pos[4].x, pos[4].y, pos[4].z, pos[0].x, pos[0].y, pos[0].z, pos[1].x, pos[1].y, pos[1].z, pos[7].x, pos[7].y, pos[7].z);
  TEST_REAL_EQUAL(torsion.toRadian(), 1.047)

  PRECISION(1E-2)
  Angle tet;
  tet = (pos[2] - pos[0]).getAngle(pos[3] - pos[0]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[2] - pos[0]).getAngle(pos[4] - pos[0]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[4] - pos[0]).getAngle(pos[3] - pos[0]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[5] - pos[1]).getAngle(pos[6] - pos[1]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[5] - pos[1]).getAngle(pos[7] - pos[1]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[7] - pos[1]).getAngle(pos[6] - pos[1]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)

RESULT

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

END_TEST
<commit_msg>*** empty log message ***<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: SteepestDescentMinimizer_test.C,v 1.5 2004/02/23 20:33:33 oliver Exp $
//

#include <BALL/CONCEPT/classTest.h>

///////////////////////////
#include <BALL/MOLMEC/MINIMIZATION/steepestDescent.h>
#include <BALL/MOLMEC/AMBER/amber.h>
#include <BALL/DATATYPE/options.h>
#include <BALL/KERNEL/PTE.h>
#include <BALL/FORMAT/HINFile.h>
#include <BALL/MATHS/analyticalGeometry.h>

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

START_TEST(ConjugateGradienMinimizer, "$Id: SteepestDescentMinimizer_test.C,v 1.5 2004/02/23 20:33:33 oliver Exp $")

using namespace BALL;

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

System S;
AmberFF FF(S);

SteepestDescentMinimizer*	em;
CHECK(SteepestDescentMinimizer::SteepestDescentMinimizer())
	em = new SteepestDescentMinimizer;
	TEST_NOT_EQUAL(em, 0)
RESULT

CHECK(SteepestDescentMinimizer::~SteepestDescentMinimizer())
	delete em;
RESULT

CHECK(SteepestDescentMinimizer::getForceField())
	SteepestDescentMinimizer em;
	TEST_EQUAL(em.getForceField(), 0)
RESULT

CHECK(SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField&))
	TEST_EQUAL(FF.isValid(), true)
	SteepestDescentMinimizer em(FF);
	TEST_EQUAL(em.getForceField(), &FF)
RESULT

CHECK(SteepestDescentMinimizer::SteepestDescentMinimizer(ForceField&, const Options&))
	Options options;
	options.set("ABC", "DEF");
	em = new SteepestDescentMinimizer(FF, options);
	TEST_EQUAL(em->getForceField(), &FF)
	TEST_EQUAL(em->options["ABC"], "DEF")
	delete em;
RESULT

CHECK(SteepestDescentMinimizer::SteepestDescentMinimizer(const SteepestDescentMinimizer&, bool))
	SteepestDescentMinimizer em1;
	SteepestDescentMinimizer em2(em1);
	bool test = (em1 == em2);
	TEST_EQUAL(test, true)
	em1.setup(FF);
	SteepestDescentMinimizer em3(em1);
	test = (em1 == em3);
	TEST_EQUAL(test, true)
	em1.setup(FF);
RESULT

CHECK(SteepestDescentMinimizer::operator = (const SteepestDescentMinimizer&))
	SteepestDescentMinimizer em1;
	SteepestDescentMinimizer em2 = em1;
	bool test = (em1 == em2);
	TEST_EQUAL(test, true)
	em1.setup(FF);
	SteepestDescentMinimizer em3 = em1;
	test = (em1 == em3);
	TEST_EQUAL(test, true)
RESULT

CHECK(SteepestDescentMinimizer::isValid() const)
	em = new SteepestDescentMinimizer;
	TEST_EQUAL(em->isValid(), false)
	delete em;
	em = new SteepestDescentMinimizer(FF);
	TEST_EQUAL(em->isValid(), true)
	delete em;
RESULT

CHECK(SteepestDescentMinimizer::setup(ForceField&))
	SteepestDescentMinimizer e_min(FF);
	TEST_EQUAL(e_min.getForceUpdateCounter(), 0)
	TEST_EQUAL(e_min.getEnergyUpdateCounter(), 0)
	bool test = (e_min.getForceField() == &FF);
	TEST_EQUAL(test, true)
RESULT

CHECK(SteepestDescentMinimizer::setup(ForceField&, const Options&))
	Options options;
	options.setInteger(EnergyMinimizer::Option::ENERGY_OUTPUT_FREQUENCY, 3456);
	SteepestDescentMinimizer e_min(FF, options);
	TEST_EQUAL(e_min.getForceUpdateCounter(), 0)
	TEST_EQUAL(e_min.getEnergyUpdateCounter(), 0)
	bool test = (e_min.getForceField() == &FF);
	TEST_EQUAL(test, true)
	TEST_EQUAL(e_min.getEnergyOutputFrequency(), 3456)
RESULT

CHECK(SteepestDescentMinimizer::specificSetup())
	SteepestDescentMinimizer em(FF);
	TEST_EQUAL(em.specificSetup(), true)
	// specificSetup() shouldn't do anything except returning true
RESULT

CHECK(SteepestDescentMinimizer::getNumberOfIteration() const)
	SteepestDescentMinimizer e_min;
	TEST_EQUAL(e_min.getNumberOfIterations(), 0)
RESULT

CHECK(SteepestDescentMinimizer::setNumberOfIteration(Size))
	SteepestDescentMinimizer e_min;
	e_min.setNumberOfIterations(4);
	TEST_EQUAL(e_min.getNumberOfIterations(), 4)
RESULT

CHECK(SteepestDescentMinimizer::getMaxNumberOfIterations())
	SteepestDescentMinimizer e_min;
	TEST_EQUAL(e_min.getMaxNumberOfIterations(), 0)
RESULT

CHECK(SteepestDescentMinimizer::setMaxNumberOfIterations(Size))
	SteepestDescentMinimizer e_min;
	e_min.setMaxNumberOfIterations(2000);
	TEST_EQUAL(e_min.getMaxNumberOfIterations(), 2000)
RESULT

CHECK(SteepestDescentMinimizer::getEnergyOutputFrequency() const)
	SteepestDescentMinimizer e_min2;
	TEST_EQUAL(e_min2.getEnergyOutputFrequency(), 0)
RESULT

CHECK(SteepestDescentMinimizer::setEnergyOutputFrequency(Size))
	SteepestDescentMinimizer e_min;
	e_min.setEnergyOutputFrequency(8);
	TEST_EQUAL(e_min.getEnergyOutputFrequency(), 8)
RESULT

CHECK(SteepestDescentMinimizer::getEnergyDifferenceBound() const)
	SteepestDescentMinimizer e_min;
	TEST_EQUAL(e_min.getEnergyDifferenceBound(), 0.0)
RESULT

CHECK(SteepestDescentMinimizer::setEnergyDifferenceBound(float))
	SteepestDescentMinimizer e_min;
	e_min.setEnergyDifferenceBound(9.0);
	TEST_EQUAL(e_min.getEnergyDifferenceBound(), 9.0)
RESULT

CHECK(SteepestDescentMinimizer::getMaximumDisplacement() const)
	SteepestDescentMinimizer e_min;
	TEST_EQUAL(e_min.getMaximumDisplacement(), 0.0)
RESULT

CHECK(SteepestDescentMinimizer::setMaximumDisplacement(float))
	SteepestDescentMinimizer e_min;
	e_min.setMaximumDisplacement(56.0);
	TEST_EQUAL(e_min.getMaximumDisplacement(), 56.0)
RESULT

CHECK(SteepestDescentMinimizer::minimize(Size, bool))
	System S;
	Molecule* m = new Molecule;
	Atom* a1 = new Atom;
	Atom* a2 = new Atom;
	S.insert(*m);
	m->insert(*a1);
	m->insert(*a2);
	a1->setPosition(Vector3(-0.5, 0, 0));
	a2->setPosition(Vector3(0.5, 0, 0));
	a1->setElement(PTE[Element::C]);
	a2->setElement(PTE[Element::C]);
	a1->setTypeName("C");
	a2->setTypeName("C");
	a1->setCharge(0.0);
	a2->setCharge(0.0);
	FF.options[AmberFF::Option::ASSIGN_CHARGES] = "false";
	FF.setup(S);
	TEST_EQUAL(FF.isValid(), true)
	PRECISION(1e-4)
	FF.updateEnergy();
	FF.updateForces();
	PRECISION(10)
	TEST_REAL_EQUAL(FF.getEnergy(), 3.42854e+06)
	SteepestDescentMinimizer cgm(FF);
	cgm.setEnergyOutputFrequency(1);
	cgm.setMaxGradient(0.01);
	TEST_EQUAL(cgm.isValid(), true)
	bool converged = cgm.minimize(20);
	TEST_EQUAL(converged, true)

	FF.updateEnergy();
	FF.updateForces();

	PRECISION(1e-3)
  TEST_REAL_EQUAL(FF.getEnergy(), -0.359813)
	PRECISION(7e-3)
  TEST_REAL_EQUAL(a1->getPosition().getDistance(a2->getPosition()), 3.81244)
RESULT

CHECK(SteepestDescentMinimizer::minimize(Size, bool) ethan)
  System S;
  HINFile f("data/ethan.hin");
  f >> S;
  FF.options[AmberFF::Option::ASSIGN_CHARGES] = "false";
  FF.setup(S);

  TEST_EQUAL(FF.isValid(), true)
  FF.updateEnergy();
  FF.updateForces();
  PRECISION(1E-4)
  TEST_REAL_EQUAL(FF.getEnergy(), 18.5605)

  SteepestDescentMinimizer sd(FF);

  sd.setEnergyOutputFrequency(5);
  sd.setMaxGradient(0.418);
	sd.setMaxNumberOfIterations(10000);
  sd.setEnergyDifferenceBound(0.00000001);

  TEST_EQUAL(sd.isValid(), true)
  FF.updateEnergy();
  FF.updateForces();
  bool result = sd.minimize(500);

  TEST_EQUAL(result, true)
  float energy = FF.updateEnergy();
  FF.updateForces();

  PRECISION(6E-2)
  TEST_REAL_EQUAL(energy, 5.906)

  AtomIterator atit;
  Vector3 pos[8];
  int i=0;

  for (atit = S.beginAtom(); +atit; ++atit)
  {
    pos[i] = atit->getPosition();
    ++i;
	}

  PRECISION(5E-2)
  Angle torsion;
  torsion = getTorsionAngle(pos[2].x, pos[2].y, pos[2].z, pos[0].x, pos[0].y, pos[0].z, pos[1].x, pos[1].y, pos[1].z, pos[6].x, pos[6].y, pos[6].z);
  TEST_REAL_EQUAL(torsion.toRadian(), 1.047)
  torsion = getTorsionAngle(pos[3].x, pos[3].y, pos[3].z, pos[0].x, pos[0].y, pos[0].z, pos[1].x, pos[1].y, pos[1].z, pos[5].x, pos[5].y, pos[5].z);
  TEST_REAL_EQUAL(torsion.toRadian(), 1.047)
  torsion = getTorsionAngle(pos[4].x, pos[4].y, pos[4].z, pos[0].x, pos[0].y, pos[0].z, pos[1].x, pos[1].y, pos[1].z, pos[7].x, pos[7].y, pos[7].z);
  TEST_REAL_EQUAL(torsion.toRadian(), 1.047)

  PRECISION(1E-2)
  Angle tet;
  tet = (pos[2] - pos[0]).getAngle(pos[3] - pos[0]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[2] - pos[0]).getAngle(pos[4] - pos[0]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[4] - pos[0]).getAngle(pos[3] - pos[0]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[5] - pos[1]).getAngle(pos[6] - pos[1]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[5] - pos[1]).getAngle(pos[7] - pos[1]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)
  tet = (pos[7] - pos[1]).getAngle(pos[6] - pos[1]);
  TEST_REAL_EQUAL(tet.toRadian(), 1.902)

RESULT

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

END_TEST
<|endoftext|>


<commit_before>//
//  SerialPort.cpp
//  MWorksCore
//
//  Created by Christopher Stawarz on 6/30/16.
//  Copyright © 2016 The MWorks Project. All rights reserved.
//

//
// NOTE: The methods used here to discover, connect to, and communicate with serial ports come from Apple's
// "Performing Serial I/O" sample code, which is available at
// https://developer.apple.com/library/mac/samplecode/SerialPortSample/Introduction/Intro.html
//

#include "SerialPort.hpp"

#include <fcntl.h>
#include <sys/ioctl.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/serial/ioss.h>
#include <IOKit/IOBSD.h>

#include <boost/scope_exit.hpp>

#include "CFObjectPtr.h"
#include "Utilities.h"

BEGIN_NAMESPACE_MW

SerialPort::SerialPort(bool blocking) :
    blocking(blocking),
    fd(-1)
{ }

SerialPort::~SerialPort() {
    disconnect();
}

bool SerialPort::connect(std::string path, speed_t baudRate) {
    if (-1 != fd) {
        merror(M_IODEVICE_MESSAGE_DOMAIN, "Serial port is already connected");
        return false;
    }

    if (!validatePath(path)) {
        return false;
    }

    // Open the serial port read/write, with no controlling terminal, and don't wait for a connection.
    // The O_NONBLOCK flag also causes subsequent I/O on the device to be non-blocking.
    if (-1 == (fd = ::open(path.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK))) {
        sysError("Cannot open serial port");
        return false;
    }

    bool shouldClose = true;
    BOOST_SCOPE_EXIT(&shouldClose, &fd) {
        if (shouldClose) {
            (void)::close(fd);
            fd = -1;
        }
    } BOOST_SCOPE_EXIT_END

    // open() follows POSIX semantics: multiple open() calls to the same file will succeed
    // unless the TIOCEXCL ioctl is issued.  This will prevent additional opens except by root-owned
    // processes.
    if (-1 == ioctl(fd, TIOCEXCL)) {
        sysError("Cannot obtain exclusive use of serial port");
        return false;
    }

    if (blocking) {
        // Now that the device is open, clear the O_NONBLOCK flag so subsequent I/O will block
        if (-1 == fcntl(fd, F_SETFL, 0)) {
            sysError("Cannot restore blocking I/O on serial port");
            return false;
        }
    }

    // Get the current options and save them, so we can restore the default settings later
    if (-1 == tcgetattr(fd, &origAttrs)) {
        sysError("Cannot obtain current serial port attributes");
        return false;
    }

    struct termios attrs = origAttrs;
    cfmakeraw(&attrs);            // Set raw input (non-canonical) mode
    if (blocking) {
        attrs.c_cc[VMIN] = 0;     // Reads block until a single byte has been received
        attrs.c_cc[VTIME] = 5;    //   or a 500ms timeout expires
    }
    cfsetspeed(&attrs, baudRate); // Set baud rate
    attrs.c_cflag |= CS8;         // Use 8-bit words
    attrs.c_cflag &= ~PARENB;     // No parity
    attrs.c_cflag &= ~CSTOPB;     // 1 stop bit
    attrs.c_cflag |= CLOCAL;      // Ignore modem status lines

    // Cause the new options to take effect immediately
    if (-1 == tcsetattr(fd, TCSANOW, &attrs)) {
        sysError("Cannot set serial port attributes");
        return false;
    }

    shouldClose = false;

    return true;
}

void SerialPort::disconnect() {
    if (-1 == fd) {
        return;
    }

    // Block until all written output has been sent to the device
    if (-1 == tcdrain(fd)) {
        sysError("Serial port drain failed");
    }

    // Restore original options
    if (-1 == tcsetattr(fd, TCSANOW, &origAttrs)) {
        sysError("Cannot restore previous serial port attributes");
    }

    if (-1 == ::close(fd)) {
        sysError("Cannot close serial port");
    }

    fd = -1;
}

ssize_t SerialPort::read(void *data, std::size_t size) {
    auto result = ::read(fd, data, size);
    if (-1 == result) {
        if (!blocking && (EAGAIN == errno)) {
            // Non-blocking read with no data available
            return 0;
        }
        sysError("Read from serial port failed");
    }
    return result;
}

ssize_t SerialPort::write(const void *data, std::size_t size) {
    auto result = ::write(fd, data, size);
    if (-1 == result) {
        sysError("Write to serial port failed");
    }
    return result;
}

bool SerialPort::validatePath(std::string &path) {
    auto classesToMatch = cf::ObjectPtr<CFMutableDictionaryRef>::owned(IOServiceMatching(kIOSerialBSDServiceValue));
    if (classesToMatch) {
        CFDictionarySetValue(classesToMatch.get(), CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
    }

    io_iterator_t matchingServices = IO_OBJECT_NULL;
    if (KERN_SUCCESS != IOServiceGetMatchingServices(kIOMasterPortDefault,
                                                     classesToMatch.release(),  // Reference is consumed by callee
                                                     &matchingServices))
    {
        merror(M_IODEVICE_MESSAGE_DOMAIN, "Failed to detect available serial devices");
        return false;
    }
    BOOST_SCOPE_EXIT(matchingServices) {
        IOObjectRelease(matchingServices);
    } BOOST_SCOPE_EXIT_END

    std::vector<std::string> devicePaths;
    io_object_t service = IO_OBJECT_NULL;
    while ((service = IOIteratorNext(matchingServices))) {
        BOOST_SCOPE_EXIT(service) {
            IOObjectRelease(service);
        } BOOST_SCOPE_EXIT_END

        auto pathAsCFString = cf::StringPtr::owned(static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(service,
                                                                                CFSTR(kIOCalloutDeviceKey),
                                                                                kCFAllocatorDefault,
                                                                                0)));
        if (pathAsCFString &&
            // Ignore devices with "Bluetooth-" in the path, which are always present
            kCFNotFound == CFStringFind(pathAsCFString.get(), CFSTR("Bluetooth-"), 0).location)
        {
            std::vector<char> buffer(CFStringGetMaximumSizeForEncoding(CFStringGetLength(pathAsCFString.get()),
                                                                       kCFStringEncodingUTF8) + 1);
            if (CFStringGetCString(pathAsCFString.get(), buffer.data(), buffer.size(), kCFStringEncodingUTF8)) {
                devicePaths.emplace_back(buffer.data());
            }
        }
    }

    if (!path.empty()) {
        if (std::find(devicePaths.begin(), devicePaths.end(), path) != devicePaths.end()) {
            // Requested path exists and is a serial device
            return true;
        }
        merror(M_IODEVICE_MESSAGE_DOMAIN, "Requested path (%s) does not exist or is not a serial device", path.c_str());
        return false;
    }

    if (devicePaths.empty()) {
        merror(M_IODEVICE_MESSAGE_DOMAIN, "No serial devices found");
        return false;
    }

    if (devicePaths.size() > 1) {
        std::ostringstream oss;
        oss << "Multiple candidate serial devices found:\n";
        for (const auto &p : devicePaths) {
            oss << "\n\t" << p;
        }
        oss << "\n\nPlease provide the explicit path for the desired device.\n";
        merror(M_IODEVICE_MESSAGE_DOMAIN, "%s", oss.str().c_str());
        return false;
    }

    // Only one device found.  Assume it's the one we want.
    path = devicePaths.front();
    return true;
}

inline void SerialPort::sysError(const std::string &msg) {
    merror(M_IODEVICE_MESSAGE_DOMAIN, "%s: %s", msg.c_str(), strerror(errno));
}

END_NAMESPACE_MW

<commit_msg>SerialPort::validatePath now canonicalizes the requested path before checking it against detected serial devices<commit_after>//
//  SerialPort.cpp
//  MWorksCore
//
//  Created by Christopher Stawarz on 6/30/16.
//  Copyright © 2016 The MWorks Project. All rights reserved.
//

//
// NOTE: The methods used here to discover, connect to, and communicate with serial ports come from Apple's
// "Performing Serial I/O" sample code, which is available at
// https://developer.apple.com/library/mac/samplecode/SerialPortSample/Introduction/Intro.html
//

#include "SerialPort.hpp"

#include <fcntl.h>
#include <sys/ioctl.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/serial/ioss.h>
#include <IOKit/IOBSD.h>

#include <boost/filesystem.hpp>
#include <boost/scope_exit.hpp>

#include "CFObjectPtr.h"
#include "Utilities.h"

BEGIN_NAMESPACE_MW

SerialPort::SerialPort(bool blocking) :
    blocking(blocking),
    fd(-1)
{ }

SerialPort::~SerialPort() {
    disconnect();
}

bool SerialPort::connect(std::string path, speed_t baudRate) {
    if (-1 != fd) {
        merror(M_IODEVICE_MESSAGE_DOMAIN, "Serial port is already connected");
        return false;
    }

    if (!validatePath(path)) {
        return false;
    }

    // Open the serial port read/write, with no controlling terminal, and don't wait for a connection.
    // The O_NONBLOCK flag also causes subsequent I/O on the device to be non-blocking.
    if (-1 == (fd = ::open(path.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK))) {
        sysError("Cannot open serial port");
        return false;
    }

    bool shouldClose = true;
    BOOST_SCOPE_EXIT(&shouldClose, &fd) {
        if (shouldClose) {
            (void)::close(fd);
            fd = -1;
        }
    } BOOST_SCOPE_EXIT_END

    // open() follows POSIX semantics: multiple open() calls to the same file will succeed
    // unless the TIOCEXCL ioctl is issued.  This will prevent additional opens except by root-owned
    // processes.
    if (-1 == ioctl(fd, TIOCEXCL)) {
        sysError("Cannot obtain exclusive use of serial port");
        return false;
    }

    if (blocking) {
        // Now that the device is open, clear the O_NONBLOCK flag so subsequent I/O will block
        if (-1 == fcntl(fd, F_SETFL, 0)) {
            sysError("Cannot restore blocking I/O on serial port");
            return false;
        }
    }

    // Get the current options and save them, so we can restore the default settings later
    if (-1 == tcgetattr(fd, &origAttrs)) {
        sysError("Cannot obtain current serial port attributes");
        return false;
    }

    struct termios attrs = origAttrs;
    cfmakeraw(&attrs);            // Set raw input (non-canonical) mode
    if (blocking) {
        attrs.c_cc[VMIN] = 0;     // Reads block until a single byte has been received
        attrs.c_cc[VTIME] = 5;    //   or a 500ms timeout expires
    }
    cfsetspeed(&attrs, baudRate); // Set baud rate
    attrs.c_cflag |= CS8;         // Use 8-bit words
    attrs.c_cflag &= ~PARENB;     // No parity
    attrs.c_cflag &= ~CSTOPB;     // 1 stop bit
    attrs.c_cflag |= CLOCAL;      // Ignore modem status lines

    // Cause the new options to take effect immediately
    if (-1 == tcsetattr(fd, TCSANOW, &attrs)) {
        sysError("Cannot set serial port attributes");
        return false;
    }

    shouldClose = false;

    return true;
}

void SerialPort::disconnect() {
    if (-1 == fd) {
        return;
    }

    // Block until all written output has been sent to the device
    if (-1 == tcdrain(fd)) {
        sysError("Serial port drain failed");
    }

    // Restore original options
    if (-1 == tcsetattr(fd, TCSANOW, &origAttrs)) {
        sysError("Cannot restore previous serial port attributes");
    }

    if (-1 == ::close(fd)) {
        sysError("Cannot close serial port");
    }

    fd = -1;
}

ssize_t SerialPort::read(void *data, std::size_t size) {
    auto result = ::read(fd, data, size);
    if (-1 == result) {
        if (!blocking && (EAGAIN == errno)) {
            // Non-blocking read with no data available
            return 0;
        }
        sysError("Read from serial port failed");
    }
    return result;
}

ssize_t SerialPort::write(const void *data, std::size_t size) {
    auto result = ::write(fd, data, size);
    if (-1 == result) {
        sysError("Write to serial port failed");
    }
    return result;
}

bool SerialPort::validatePath(std::string &path) {
    auto classesToMatch = cf::ObjectPtr<CFMutableDictionaryRef>::owned(IOServiceMatching(kIOSerialBSDServiceValue));
    if (classesToMatch) {
        CFDictionarySetValue(classesToMatch.get(), CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
    }

    io_iterator_t matchingServices = IO_OBJECT_NULL;
    if (KERN_SUCCESS != IOServiceGetMatchingServices(kIOMasterPortDefault,
                                                     classesToMatch.release(),  // Reference is consumed by callee
                                                     &matchingServices))
    {
        merror(M_IODEVICE_MESSAGE_DOMAIN, "Failed to detect available serial devices");
        return false;
    }
    BOOST_SCOPE_EXIT(matchingServices) {
        IOObjectRelease(matchingServices);
    } BOOST_SCOPE_EXIT_END

    std::vector<std::string> devicePaths;
    io_object_t service = IO_OBJECT_NULL;
    while ((service = IOIteratorNext(matchingServices))) {
        BOOST_SCOPE_EXIT(service) {
            IOObjectRelease(service);
        } BOOST_SCOPE_EXIT_END

        auto pathAsCFString = cf::StringPtr::owned(static_cast<CFStringRef>(IORegistryEntryCreateCFProperty(service,
                                                                                CFSTR(kIOCalloutDeviceKey),
                                                                                kCFAllocatorDefault,
                                                                                0)));
        if (pathAsCFString &&
            // Ignore devices with "Bluetooth-" in the path, which are always present
            kCFNotFound == CFStringFind(pathAsCFString.get(), CFSTR("Bluetooth-"), 0).location)
        {
            std::vector<char> buffer(CFStringGetMaximumSizeForEncoding(CFStringGetLength(pathAsCFString.get()),
                                                                       kCFStringEncodingUTF8) + 1);
            if (CFStringGetCString(pathAsCFString.get(), buffer.data(), buffer.size(), kCFStringEncodingUTF8)) {
                devicePaths.emplace_back(buffer.data());
            }
        }
    }

    if (!path.empty()) {
        // Try to canonicalize the path (make absolute, resolve symbolic links, etc.)
        boost::system::error_code ec;
        auto canonPath = boost::filesystem::canonical(boost::filesystem::path(path), ec);
        if (!ec) {
            path = canonPath.string();
        }

        if (std::find(devicePaths.begin(), devicePaths.end(), path) != devicePaths.end()) {
            // Requested path exists and is a serial device
            return true;
        }
        merror(M_IODEVICE_MESSAGE_DOMAIN, "Requested path (%s) does not exist or is not a serial device", path.c_str());
        return false;
    }

    if (devicePaths.empty()) {
        merror(M_IODEVICE_MESSAGE_DOMAIN, "No serial devices found");
        return false;
    }

    if (devicePaths.size() > 1) {
        std::ostringstream oss;
        oss << "Multiple candidate serial devices found:\n";
        for (const auto &p : devicePaths) {
            oss << "\n\t" << p;
        }
        oss << "\n\nPlease provide the explicit path for the desired device.\n";
        merror(M_IODEVICE_MESSAGE_DOMAIN, "%s", oss.str().c_str());
        return false;
    }

    // Only one device found.  Assume it's the one we want.
    path = devicePaths.front();
    return true;
}

inline void SerialPort::sysError(const std::string &msg) {
    merror(M_IODEVICE_MESSAGE_DOMAIN, "%s: %s", msg.c_str(), strerror(errno));
}

END_NAMESPACE_MW

<|endoftext|>


<commit_before>#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <time.h>

// Shader sources
const GLchar* vertexSource =
    "#version 150 core\n"
    "in vec2 position;"
    "void main() {"
    "   gl_Position = vec4(position, 0.0, 1.0);"
    "}";

const GLchar* fragmentSource =
    "#version 150 core\n"
    "out vec4 outColor;"
	"uniform vec3 triangleColor;"
    "void main() {"
    "   outColor = vec4(triangleColor, 1.0);"
    "}";

int main()
{
	//initializing glfw
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
	GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr); // Windowed
	//GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", glfwGetPrimaryMonitor(), nullptr); // Fullscreen
	glfwMakeContextCurrent(window);

	//initializing glew
	glewExperimental = GL_TRUE;
	glewInit();

	// Create Vertex Array Object
	GLuint vao;
	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);

	// Create a Vertex Buffer Object and copy the vertex data to it
	GLuint vbo;
	glGenBuffers(1, &vbo);

	GLfloat vertices[] = {
		0.0f, 0.5f,
		0.5f, -0.5f,
		-0.5f, -0.5f
	};

	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// Create and compile the vertex shader
	GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexSource, NULL);
	glCompileShader(vertexShader);

	// Create and compile the fragment shader
	GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
	glCompileShader(fragmentShader);

	// Link the vertex and fragment shader into a shader program
	GLuint shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glBindFragDataLocation(shaderProgram, 0, "outColor");
	glLinkProgram(shaderProgram);
	glUseProgram(shaderProgram);

	// Specify the layout of the vertex data
	GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
	glEnableVertexAttribArray(posAttrib);
	glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);

	// Get the location of the color uniform
	GLint uniColor = glGetUniformLocation(shaderProgram, "triangleColor");

	//basic main glfw loop
	while (!glfwWindowShouldClose(window))
	{
		glfwPollEvents();

		if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
			glfwSetWindowShouldClose(window, GL_TRUE);

		// Set the color of the triangle
		GLfloat time = (GLfloat)glfwGetTime();
		std::cout << (sin(time) + 1.0f) / 2.0f << std::endl;

		glUniform3f(uniColor, (sin(time) + 1.0f) / 2.0f, 0.0f, 0.0f);

		// Clear the screen to black
		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		// Draw a triangle from the 3 vertices
		glDrawArrays(GL_TRIANGLES, 0, 3);
		glfwSwapBuffers(window);

	}
	glDeleteProgram(shaderProgram);
	glDeleteShader(fragmentShader);
	glDeleteShader(vertexShader);

	glDeleteBuffers(1, &vbo);

	glDeleteVertexArrays(1, &vao);
	glfwTerminate();
	return 0;
}<commit_msg>Added another triangle, also push test<commit_after>#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <time.h>

// Shader sources
const GLchar* vertexSource =
    "#version 150 core\n"
    "in vec2 position;"
    "void main() {"
    "   gl_Position = vec4(position, 0.0, 1.0);"
    "}";

const GLchar* fragmentSource =
    "#version 150 core\n"
    "out vec4 outColor;"
	"uniform vec3 triangleColor;"
    "void main() {"
    "   outColor = vec4(triangleColor, 1.0);"
    "}";

int main()
{
	//initializing glfw
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
	GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr); // Windowed
	//GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", glfwGetPrimaryMonitor(), nullptr); // Fullscreen
	glfwMakeContextCurrent(window);

	//initializing glew
	glewExperimental = GL_TRUE;
	glewInit();

	// Create Vertex Array Object
	GLuint vao;
	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);

	// Create a Vertex Buffer Object and copy the vertex data to it
	GLuint vbo;
	glGenBuffers(1, &vbo);

	GLfloat vertices[] = {
		0.0f, 0.5f,
		0.5f, -0.5f,
		-0.5f, -0.5f,
		0.25f, 0.5f,
		1.25f, 0.5f,
		0.75f, -0.5f
	};

	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// Create and compile the vertex shader
	GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexSource, NULL);
	glCompileShader(vertexShader);

	// Create and compile the fragment shader
	GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
	glCompileShader(fragmentShader);

	// Link the vertex and fragment shader into a shader program
	GLuint shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glBindFragDataLocation(shaderProgram, 0, "outColor");
	glLinkProgram(shaderProgram);
	glUseProgram(shaderProgram);

	// Specify the layout of the vertex data
	GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
	glEnableVertexAttribArray(posAttrib);
	glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);

	// Get the location of the color uniform
	GLint uniColor = glGetUniformLocation(shaderProgram, "triangleColor");

	//basic main glfw loop
	while (!glfwWindowShouldClose(window))
	{
		glfwPollEvents();

		if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
			glfwSetWindowShouldClose(window, GL_TRUE);

		// Set the color of the triangle
		GLfloat time = (GLfloat)glfwGetTime();
		std::cout << (sin(time) + 1.0f) / 2.0f << std::endl;

		glUniform3f(uniColor, (sin(time) + 1.0f) / 2.0f, 0.0f, 0.0f);

		// Clear the screen to black
		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		// Draw a triangle from the 3 vertices
		glDrawArrays(GL_TRIANGLES, 0, 6);
		glfwSwapBuffers(window);

	}
	glDeleteProgram(shaderProgram);
	glDeleteShader(fragmentShader);
	glDeleteShader(vertexShader);

	glDeleteBuffers(1, &vbo);

	glDeleteVertexArrays(1, &vao);
	glfwTerminate();
	return 0;
}<|endoftext|>


<commit_before><commit_msg>Fix fd leak in starter<commit_after><|endoftext|>