<commit_before>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Logging functions.
  */

#include "thcrap.h"
#include <io.h>
#include <fcntl.h>

// -------
// Globals
// -------
static FILE *log_file = NULL;
static int console_open = 0;
// For checking nested thcrap instances that access the same log file.
// We only want to print an error message for the first instance.
static HANDLE log_filemapping = INVALID_HANDLE_VALUE;
static const char LOG[] = "logs/thcrap_log.txt";
static const char LOG_ROTATED[] = "logs/thcrap_log.%d.txt";
static const int ROTATIONS = 5; // Number of backups to keep
static void (*log_print_hook)(const char*) = NULL;
static void(*log_nprint_hook)(const char*, size_t) = NULL;
static HWND mbox_owner_hwnd = NULL; // Set by log_mbox_set_owner
// -----------------------

struct lasterror_t {
	char str[DECIMAL_DIGITS_BOUND(DWORD) + 1];
};

THREAD_LOCAL(lasterror_t, lasterror_tls, nullptr, nullptr);

const char* lasterror_str_for(DWORD err)
{
	switch(err) {
	case ERROR_SHARING_VIOLATION:
		return "File in use";
	case ERROR_MOD_NOT_FOUND:
		return "File not found";
	default: // -Wswitch...
		break;
	}
	auto str = lasterror_tls_get();
	if(!str) {
		static lasterror_t lasterror_static;
		str = &lasterror_static;
	}
	snprintf(str->str, sizeof(str->str), "%lu", err);
	return str->str;
}

const char* lasterror_str()
{
	return lasterror_str_for(GetLastError());
}

void log_set_hook(void(*hookproc)(const char*), void(*hookproc2)(const char*,size_t)){
	log_print_hook = hookproc;
	log_nprint_hook = hookproc2;
}

// Rotation
// --------
void log_fn_for_rotation(char *fn, int rotnum)
{
	if(rotnum == 0) {
		strcpy(fn, LOG);
	} else {
		sprintf(fn, LOG_ROTATED, rotnum);
	}
}

void log_rotate(void)
{
	size_t rot_fn_len = MAX(sizeof(LOG_ROTATED), sizeof(LOG));
	VLA(char, rot_from, rot_fn_len);
	VLA(char, rot_to, rot_fn_len);

	for(int rotation = ROTATIONS; rotation > 0; rotation--) {
		log_fn_for_rotation(rot_from, rotation - 1);
		log_fn_for_rotation(rot_to, rotation);
		MoveFileExU(rot_from, rot_to, MOVEFILE_REPLACE_EXISTING);
	}

	VLA_FREE(rot_from);
	VLA_FREE(rot_to);
}
// --------

#define VLA_VSPRINTF(str, va) \
	size_t str##_full_len = _vscprintf(str, va) + 1; \
	VLA(char, str##_full, str##_full_len); \
	/* vs*n*printf is not available in msvcrt.dll. Doesn't matter anyway. */ \
	vsprintf(str##_full, str, va);

void log_print(const char *str)
{
	if(console_open) {
		fprintf(stdout, "%s", str);
	}
	if(log_file) {
		fprintf(log_file, "%s", str);
		fflush(log_file);
	}
	if(log_print_hook) {
		log_print_hook(str);
	}
}

void log_nprint(const char *str, size_t n)
{
	if(console_open) {
		fwrite(str, n, 1, stdout);
	}
	if(log_file) {
		fwrite(str, n, 1, log_file);
	}
	if (log_nprint_hook) {
		log_nprint_hook(str, n);
	}
}

void log_vprintf(const char *str, va_list va)
{
	if(str) {
		VLA_VSPRINTF(str, va);
		log_print(str_full);
		VLA_FREE(str_full);
	}
}

void log_printf(const char *str, ...)
{
	if(str) {
		va_list va;
		va_start(va, str);
		log_vprintf(str, va);
		va_end(va);
	}
}

/**
  * Message box functions.
  */

struct EnumStatus
{
	HWND hwnd;
	int w;
	int h;
};

static BOOL CALLBACK enumWindowProc(HWND hwnd, LPARAM lParam)
{
	EnumStatus *status = (EnumStatus*)lParam;

	if (!IsWindowVisible(hwnd)) {
		return TRUE;
	}

	DWORD pid;
	GetWindowThreadProcessId(hwnd, &pid);
	if (pid != GetCurrentProcessId()) {
		return TRUE;
	}

	RECT rect;
	GetWindowRect(hwnd, &rect);
	int w = rect.right - rect.left;
	int h = rect.bottom - rect.top;
	if (w * h > status->w * status->h) {
		status->hwnd = hwnd;
	}

	return TRUE;
}

static HWND guess_mbox_owner()
{
	// If an owner have been set, easy - just return it.
	if (mbox_owner_hwnd) {
		return mbox_owner_hwnd;
	}

	// Time to guess. If the current thread has an active window, it's probably a good window to steal.
	HWND hwnd = GetActiveWindow();
	if (hwnd) {
		return hwnd;
	}

	// It's getting harder. Look at all the top-level visible windows of our processes, and take the biggest one.
	EnumStatus status;
	status.hwnd = nullptr;
	status.w = 10; // Ignore windows smaller than 10x10
	status.h = 10;
	EnumWindows(enumWindowProc, (LPARAM)&status);
	if (status.hwnd) {
		return status.hwnd;
	}

	// Let's hope our process is allowed to take the focus.
	return nullptr;
}

int log_mbox(const char *caption, const UINT type, const char *text)
{
	if(!caption) {
		caption = PROJECT_NAME();
	}
	log_print("---------------------------\n");
	log_printf("%s\n", text);
	log_print("---------------------------\n");
	return MessageBox(guess_mbox_owner(), text, caption, type);
}

int log_vmboxf(const char *caption, const UINT type, const char *text, va_list va)
{
	int ret = 0;
	if(text) {
		VLA_VSPRINTF(text, va);
		ret = log_mbox(caption, type, text_full);
		VLA_FREE(text_full);
	}
	return ret;
}

int log_mboxf(const char *caption, const UINT type, const char *text, ...)
{
	int ret = 0;
	if(text) {
		va_list va;
		va_start(va, text);
		ret = log_vmboxf(caption, type, text, va);
		va_end(va);
	}
	return ret;
}

void log_mbox_set_owner(HWND hwnd)
{
	mbox_owner_hwnd = hwnd;
}

static void OpenConsole(void)
{
	if(console_open) {
		return;
	}
	AllocConsole();

	// To match the behavior of the native Windows console, Wine additionally
	// needs read rights because its WriteConsole() implementation calls
	// GetConsoleMode(), and setvbuf() because… I don't know?
	freopen("CONOUT$", "w+b", stdout);
	setvbuf(stdout, NULL, _IONBF, 0);

	/// This breaks all normal, unlogged printf() calls to stdout!
	// _setmode(_fileno(stdout), _O_U16TEXT);

	console_open = 1;
}

/// Per-module loggers
/// ------------------
std::nullptr_t logger_t::verrorf(const char *text, va_list va) const
{
	auto mbox = [this, va] (const char *str) {
		log_vmboxf(err_caption, MB_OK | MB_ICONERROR, str, va);
	};
	if(prefix) {
		std::string prefixed = prefix + std::string(text);
		mbox(prefixed.c_str());
	} else {
		mbox(text);
	}
	return nullptr;
}

std::nullptr_t logger_t::errorf(const char *text, ...) const
{
	va_list va;
	va_start(va, text);
	auto ret = verrorf(text, va);
	va_end(va);
	return ret;
}
/// ------------------

void log_init(int console)
{
	CreateDirectoryU("logs", NULL);
	log_rotate();

	// Using CreateFile, _open_osfhandle and _fdopen instead of plain fopen because we need the flag FILE_SHARE_DELETE for log rotation
	HANDLE log_handle = CreateFileU(LOG, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
	if (log_handle != INVALID_HANDLE_VALUE) {
		int fd = _open_osfhandle((intptr_t)log_handle, _O_TEXT);
		log_file = _fdopen(fd, "wt");
	}
#ifdef _DEBUG
	OpenConsole();
#else
	if(console) {
		OpenConsole();
	}
	if(log_file) {
		size_t i;
		size_t line_len = strlen(PROJECT_NAME()) + strlen(" logfile") + 1;
		VLA(unsigned char, line, line_len * UTF8_MUL);

		for(i = 0; i < line_len - 1; i++) {
			// HARRY UP, anyone?
			line[i*3+0] = 0xe2;
			line[i*3+1] = 0x80;
			line[i*3+2] = 0x95;
		}
		line[i*3] = 0;

		fprintf(log_file, "%s\n", line);
		fprintf(log_file, "%s logfile\n", PROJECT_NAME());
		fprintf(log_file, "Branch: %s\n", PROJECT_BRANCH());
		fprintf(log_file, "Version: %s\n", PROJECT_VERSION_STRING());
		fprintf(log_file, "Build time: "  __DATE__ " " __TIME__ "\n");
#if defined(BUILDER_NAME_W)
		{
			const wchar_t *builder = BUILDER_NAME_W;
			UTF8_DEC(builder);
			UTF8_CONV(builder);
			fprintf(log_file, "Built by: %s\n", builder_utf8);
			UTF8_FREE(builder);
		}
#elif defined(BUILDER_NAME)
		fprintf(log_file, "Built by: %s\n", BUILDER_NAME);
#endif
		fprintf(log_file, "Command line: %s\n", GetCommandLineU());
		fprintf(log_file, "%s\n\n", line);
		fflush(log_file);
		VLA_FREE(line);
	}
#endif
	size_t cur_dir_len = GetCurrentDirectoryU(0, nullptr);
	size_t full_fn_len = cur_dir_len + sizeof(LOG);
	VLA(char, full_fn, full_fn_len);
	defer(VLA_FREE(full_fn));
	GetCurrentDirectoryU(cur_dir_len, full_fn);
	full_fn[cur_dir_len - 1] = '/';
	full_fn[cur_dir_len] = '\0';
	str_slash_normalize(full_fn); // Necessary!
	memcpy(full_fn + cur_dir_len, LOG, sizeof(LOG));

	log_filemapping = CreateFileMappingU(
		INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 1, full_fn
	);
	if(!log_file && GetLastError() != ERROR_ALREADY_EXISTS) {
		auto ret = log_mboxf(nullptr, MB_OKCANCEL | MB_ICONHAND,
			"Error creating %s: %s\n"
			"\n"
			"Logging will be unavailable. "
			"Further writes to this directory are likely to fail as well. "
			"Moving %s to a different directory will probably fix this.\n"
			"\n"
			"Continue?",
			full_fn, strerror(errno), PROJECT_NAME_SHORT()
		);
		if(ret == IDCANCEL) {
			auto pExitProcess = ((void (__stdcall*)(UINT))detour_top(
				"kernel32.dll", "ExitProcess", (FARPROC)thcrap_ExitProcess
			));
			pExitProcess(-1);
		}
	}
}

void log_exit(void)
{
	if(console_open) {
		FreeConsole();
	}
	if(log_file) {
		CloseHandle(log_filemapping);
		fclose(log_file);
		log_file = NULL;
	}
}
<commit_msg>thcrap: Made logging line generation less dumb<commit_after>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Logging functions.
  */

#include "thcrap.h"
#include <io.h>
#include <fcntl.h>

// -------
// Globals
// -------
static FILE *log_file = NULL;
static bool console_open = false;
// For checking nested thcrap instances that access the same log file.
// We only want to print an error message for the first instance.
static HANDLE log_filemapping = INVALID_HANDLE_VALUE;
static const char LOG[] = "logs/thcrap_log.txt";
static const char LOG_ROTATED[] = "logs/thcrap_log.%d.txt";
static const int ROTATIONS = 5; // Number of backups to keep
static void (*log_print_hook)(const char*) = NULL;
static void(*log_nprint_hook)(const char*, size_t) = NULL;
static HWND mbox_owner_hwnd = NULL; // Set by log_mbox_set_owner
// -----------------------

struct lasterror_t {
	char str[DECIMAL_DIGITS_BOUND(DWORD) + 1];
};

THREAD_LOCAL(lasterror_t, lasterror_tls, nullptr, nullptr);

const char* lasterror_str_for(DWORD err)
{
	switch(err) {
	case ERROR_SHARING_VIOLATION:
		return "File in use";
	case ERROR_MOD_NOT_FOUND:
		return "File not found";
	default: // -Wswitch...
		break;
	}
	auto str = lasterror_tls_get();
	if(!str) {
		static lasterror_t lasterror_static;
		str = &lasterror_static;
	}
	snprintf(str->str, sizeof(str->str), "%lu", err);
	return str->str;
}

const char* lasterror_str()
{
	return lasterror_str_for(GetLastError());
}

void log_set_hook(void(*hookproc)(const char*), void(*hookproc2)(const char*,size_t)){
	log_print_hook = hookproc;
	log_nprint_hook = hookproc2;
}

// Rotation
// --------
void log_fn_for_rotation(char *fn, int rotnum)
{
	if(rotnum == 0) {
		strcpy(fn, LOG);
	} else {
		sprintf(fn, LOG_ROTATED, rotnum);
	}
}

void log_rotate(void)
{
	size_t rot_fn_len = MAX(sizeof(LOG_ROTATED), sizeof(LOG));
	VLA(char, rot_from, rot_fn_len);
	VLA(char, rot_to, rot_fn_len);

	for(int rotation = ROTATIONS; rotation > 0; rotation--) {
		log_fn_for_rotation(rot_from, rotation - 1);
		log_fn_for_rotation(rot_to, rotation);
		MoveFileExU(rot_from, rot_to, MOVEFILE_REPLACE_EXISTING);
	}

	VLA_FREE(rot_from);
	VLA_FREE(rot_to);
}
// --------

#define VLA_VSPRINTF(str, va) \
	size_t str##_full_len = _vscprintf(str, va) + 1; \
	VLA(char, str##_full, str##_full_len); \
	/* vs*n*printf is not available in msvcrt.dll. Doesn't matter anyway. */ \
	vsprintf(str##_full, str, va);

void log_print(const char *str)
{
	if(console_open) {
		fprintf(stdout, "%s", str);
	}
	if(log_file) {
		fprintf(log_file, "%s", str);
		fflush(log_file);
	}
	if(log_print_hook) {
		log_print_hook(str);
	}
}

void log_nprint(const char *str, size_t n)
{
	if(console_open) {
		fwrite(str, n, 1, stdout);
	}
	if(log_file) {
		fwrite(str, n, 1, log_file);
	}
	if (log_nprint_hook) {
		log_nprint_hook(str, n);
	}
}

void log_vprintf(const char *str, va_list va)
{
	if(str) {
		VLA_VSPRINTF(str, va);
		log_print(str_full);
		VLA_FREE(str_full);
	}
}

void log_printf(const char *str, ...)
{
	if(str) {
		va_list va;
		va_start(va, str);
		log_vprintf(str, va);
		va_end(va);
	}
}

/**
  * Message box functions.
  */

struct EnumStatus
{
	HWND hwnd;
	int w;
	int h;
};

static BOOL CALLBACK enumWindowProc(HWND hwnd, LPARAM lParam)
{
	EnumStatus *status = (EnumStatus*)lParam;

	if (!IsWindowVisible(hwnd)) {
		return TRUE;
	}

	DWORD pid;
	GetWindowThreadProcessId(hwnd, &pid);
	if (pid != GetCurrentProcessId()) {
		return TRUE;
	}

	RECT rect;
	GetWindowRect(hwnd, &rect);
	int w = rect.right - rect.left;
	int h = rect.bottom - rect.top;
	if (w * h > status->w * status->h) {
		status->hwnd = hwnd;
	}

	return TRUE;
}

static HWND guess_mbox_owner()
{
	// If an owner have been set, easy - just return it.
	if (mbox_owner_hwnd) {
		return mbox_owner_hwnd;
	}

	// Time to guess. If the current thread has an active window, it's probably a good window to steal.
	HWND hwnd = GetActiveWindow();
	if (hwnd) {
		return hwnd;
	}

	// It's getting harder. Look at all the top-level visible windows of our processes, and take the biggest one.
	EnumStatus status;
	status.hwnd = nullptr;
	status.w = 10; // Ignore windows smaller than 10x10
	status.h = 10;
	EnumWindows(enumWindowProc, (LPARAM)&status);
	if (status.hwnd) {
		return status.hwnd;
	}

	// Let's hope our process is allowed to take the focus.
	return nullptr;
}

int log_mbox(const char *caption, const UINT type, const char *text)
{
	log_printf(
		"---------------------------\n"
		"%s\n"
		"---------------------------\n"
		, text
	);
	return MessageBox(guess_mbox_owner(), text, (caption ? caption : PROJECT_NAME), type);
}

int log_vmboxf(const char *caption, const UINT type, const char *text, va_list va)
{
	int ret = 0;
	if(text) {
		VLA_VSPRINTF(text, va);
		ret = log_mbox(caption, type, text_full);
		VLA_FREE(text_full);
	}
	return ret;
}

int log_mboxf(const char *caption, const UINT type, const char *text, ...)
{
	int ret = 0;
	if(text) {
		va_list va;
		va_start(va, text);
		ret = log_vmboxf(caption, type, text, va);
		va_end(va);
	}
	return ret;
}

void log_mbox_set_owner(HWND hwnd)
{
	mbox_owner_hwnd = hwnd;
}

static void OpenConsole(void)
{
	if(console_open) {
		return;
	}
	AllocConsole();

	// To match the behavior of the native Windows console, Wine additionally
	// needs read rights because its WriteConsole() implementation calls
	// GetConsoleMode(), and setvbuf() because… I don't know?
	freopen("CONOUT$", "w+b", stdout);
	setvbuf(stdout, NULL, _IONBF, 0);

	/// This breaks all normal, unlogged printf() calls to stdout!
	// _setmode(_fileno(stdout), _O_U16TEXT);

	console_open = true;
}

/// Per-module loggers
/// ------------------
std::nullptr_t logger_t::verrorf(const char *text, va_list va) const
{
	auto mbox = [this, va] (const char *str) {
		log_vmboxf(err_caption, MB_OK | MB_ICONERROR, str, va);
	};
	if(prefix) {
		std::string prefixed = prefix + std::string(text);
		mbox(prefixed.c_str());
	} else {
		mbox(text);
	}
	return nullptr;
}

std::nullptr_t logger_t::errorf(const char *text, ...) const
{
	va_list va;
	va_start(va, text);
	auto ret = verrorf(text, va);
	va_end(va);
	return ret;
}
/// ------------------

void log_init(int console)
{
	CreateDirectoryU("logs", NULL);
	log_rotate();

	// Using CreateFile, _open_osfhandle and _fdopen instead of plain fopen because we need the flag FILE_SHARE_DELETE for log rotation
	HANDLE log_handle = CreateFileU(LOG, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
	if (log_handle != INVALID_HANDLE_VALUE) {
		int fd = _open_osfhandle((intptr_t)log_handle, _O_TEXT);
		log_file = _fdopen(fd, "wt");
	}
#ifdef _DEBUG
	OpenConsole();
#else
	if(console) {
		OpenConsole();
	}
	if(log_file) {

		constexpr std::string_view DashUChar = u8"―";

		const size_t line_len = (strlen(PROJECT_NAME) + strlen(" logfile")) * DashUChar.length();
		VLA(char, line, line_len + 1);
		line[line_len] = '\0';

		for (size_t i = 0; i < line_len; i += DashUChar.length()) {
			memcpy(&line[i], DashUChar.data(), DashUChar.length());
		}

		fprintf(log_file, "%s\n", line);
		fprintf(log_file, "%s logfile\n", PROJECT_NAME);
		fprintf(log_file, "Branch: %s\n", PROJECT_BRANCH);
		fprintf(log_file, "Version: %s\n", PROJECT_VERSION_STRING);
		fprintf(log_file, "Build time: "  __DATE__ " " __TIME__ "\n");
#if defined(BUILDER_NAME_W)
		{
			const wchar_t *builder = BUILDER_NAME_W;
			UTF8_DEC(builder);
			UTF8_CONV(builder);
			fprintf(log_file, "Built by: %s\n", builder_utf8);
			UTF8_FREE(builder);
		}
#elif defined(BUILDER_NAME)
		fprintf(log_file, "Built by: %s\n", BUILDER_NAME);
#endif
		fprintf(log_file, "Command line: %s\n", GetCommandLineU());
		fprintf(log_file, "%s\n\n", line);
		fflush(log_file);
		VLA_FREE(line);
	}
#endif
	size_t cur_dir_len = GetCurrentDirectoryU(0, nullptr);
	size_t full_fn_len = cur_dir_len + sizeof(LOG);
	VLA(char, full_fn, full_fn_len);
	defer(VLA_FREE(full_fn));
	GetCurrentDirectoryU(cur_dir_len, full_fn);
	full_fn[cur_dir_len - 1] = '/';
	full_fn[cur_dir_len] = '\0';
	str_slash_normalize(full_fn); // Necessary!
	memcpy(full_fn + cur_dir_len, LOG, sizeof(LOG));

	log_filemapping = CreateFileMappingU(
		INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 1, full_fn
	);
	if(!log_file && GetLastError() != ERROR_ALREADY_EXISTS) {
		auto ret = log_mboxf(nullptr, MB_OKCANCEL | MB_ICONHAND,
			"Error creating %s: %s\n"
			"\n"
			"Logging will be unavailable. "
			"Further writes to this directory are likely to fail as well. "
			"Moving %s to a different directory will probably fix this.\n"
			"\n"
			"Continue?",
			full_fn, strerror(errno), PROJECT_NAME_SHORT
		);
		if(ret == IDCANCEL) {
			auto pExitProcess = ((void (__stdcall*)(UINT))detour_top(
				"kernel32.dll", "ExitProcess", (FARPROC)thcrap_ExitProcess
			));
			pExitProcess(-1);
		}
	}
}

void log_exit(void)
{
	if(console_open) {
		FreeConsole();
	}
	if(log_file) {
		CloseHandle(log_filemapping);
		fclose(log_file);
		log_file = NULL;
	}
}
<|endoftext|>


<commit_before>// -*- mode: c++; coding: utf-8 -*-
/*! @file cell.cpp
    @brief Implementation of Cell class
*/
#include "cell.hpp"

#include <iostream>
#include <sstream>

#include <boost/program_options.hpp>

#include <cxxwtils/prandom.hpp>
#include <cxxwtils/iostr.hpp>

namespace tumopp {

double Cell::BIRTH_RATE_;
double Cell::DEATH_RATE_;
double Cell::DEATH_PROB_;
double Cell::MIGRATION_RATE_;
double Cell::GAMMA_SHAPE_;
double Cell::PROB_SYMMETRIC_DIVISION_;
size_t Cell::MAX_PROLIFERATION_CAPACITY_;
double Cell::MUTATION_RATE_;
double Cell::DRIVER_RATE_BIRTH_;
double Cell::DRIVER_RATE_DEATH_;
double Cell::DRIVER_RATE_MIGRA_;
double Cell::DRIVER_MEAN_BIRTH_;
double Cell::DRIVER_MEAN_DEATH_;
double Cell::DRIVER_MEAN_MIGRA_;
double Cell::DRIVER_SD_BIRTH_;
double Cell::DRIVER_SD_DEATH_;
double Cell::DRIVER_SD_MIGRA_;

namespace {
    std::bernoulli_distribution BERN_BIRTH;
    std::bernoulli_distribution BERN_DEATH;
    std::bernoulli_distribution BERN_MIGRA;
    std::normal_distribution<double> GAUSS_BIRTH;
    std::normal_distribution<double> GAUSS_DEATH;
    std::normal_distribution<double> GAUSS_MIGRA;
}

//! Program options
/*! @return Program options description

    Command line option | Symbol              | Variable
    ------------------- | ------------------- | -------------------------
    `-b,--beta0`        | \f$\beta_0\f$       | Cell::BIRTH_RATE_
    `-d,--delta0`       | \f$\delta_0\f$      | Cell::DEATH_RATE_
    `-a,--alpha0`       | \f$\alpha_0\f$      | Cell::DEATH_PROB_
    `-m,--rho0`         | \f$\rho_0\f$        | Cell::MIGRATION_RATE_
    `-k,--shape`        | \f$k\f$             | Cell::GAMMA_SHAPE_
    `-p,--symmetric`    | \f$p_s\f$           | Cell::PROB_SYMMETRIC_DIVISION_
    `-r,--prolif`       | \f$\omega_{\max}\f$ | Cell::MAX_PROLIFERATION_CAPACITY_
    `-u,--mutation`     | \f$\mu\f$           | Cell::MUTATION_RATE_
    `--ub`              |                     | Cell::DRIVER_RATE_BIRTH_
    `--ud`              |                     | Cell::DRIVER_RATE_DEATH_
    `--um`              |                     | Cell::DRIVER_RATE_MIGRA_
    `--mb`              |                     | Cell::DRIVER_MEAN_BIRTH_
    `--md`              |                     | Cell::DRIVER_MEAN_DEATH_
    `--mm`              |                     | Cell::DRIVER_MEAN_MIGRA_
    `--sb`              |                     | Cell::DRIVER_SD_BIRTH_
    `--sd`              |                     | Cell::DRIVER_SD_DEATH_
    `--sm`              |                     | Cell::DRIVER_SD_MIGRA_
*/
boost::program_options::options_description Cell::opt_description() {
    namespace po = boost::program_options;
    po::options_description desc{"Cell"};
    desc.add_options()
        ("beta0,b", po::value(&BIRTH_RATE_)->default_value(1.0))
        ("delta0,d", po::value(&DEATH_RATE_)->default_value(0.0))
        ("alpha0,a", po::value(&DEATH_PROB_)->default_value(0.0))
        ("rho0,m", po::value(&MIGRATION_RATE_)->default_value(0.0))
        ("shape,k", po::value(&GAMMA_SHAPE_)->default_value(1.0))
        ("symmetric,p", po::value(&PROB_SYMMETRIC_DIVISION_)->default_value(1.0))
        ("prolif,r", po::value(&MAX_PROLIFERATION_CAPACITY_)->default_value(10))
        ("mutation,u", po::value(&MUTATION_RATE_)->default_value(1e-1))
        ("ub", po::value(&DRIVER_RATE_BIRTH_)->default_value(0.0))
        ("ud", po::value(&DRIVER_RATE_DEATH_)->default_value(0.0))
        ("um", po::value(&DRIVER_RATE_MIGRA_)->default_value(0.0))
        ("mb", po::value(&DRIVER_MEAN_BIRTH_)->default_value(0.0))
        ("md", po::value(&DRIVER_MEAN_DEATH_)->default_value(0.0))
        ("mm", po::value(&DRIVER_MEAN_MIGRA_)->default_value(0.0))
        ("sb", po::value(&DRIVER_SD_BIRTH_)->default_value(0.0))
        ("sd", po::value(&DRIVER_SD_DEATH_)->default_value(0.0))
        ("sm", po::value(&DRIVER_SD_MIGRA_)->default_value(0.0))
    ;
    return desc;
}

void Cell::init_distributions() {
    BERN_BIRTH = std::bernoulli_distribution(DRIVER_RATE_BIRTH_);
    BERN_DEATH = std::bernoulli_distribution(DRIVER_RATE_DEATH_);
    BERN_MIGRA = std::bernoulli_distribution(DRIVER_RATE_MIGRA_);
    GAUSS_BIRTH = std::normal_distribution<double>(DRIVER_MEAN_BIRTH_, DRIVER_SD_BIRTH_);
    GAUSS_DEATH = std::normal_distribution<double>(DRIVER_MEAN_DEATH_, DRIVER_SD_DEATH_);
    GAUSS_MIGRA = std::normal_distribution<double>(DRIVER_MEAN_MIGRA_, DRIVER_SD_MIGRA_);
}

Cell::Cell(const Cell& other):
    coord_(other.coord_),
    birth_rate_(other.birth_rate_),
    death_rate_(other.death_rate_),
    migra_rate_(other.migra_rate_),
    type_(other.type_),
    proliferation_capacity_(other.proliferation_capacity_),
    genealogy_(other.genealogy_) {
    if (type_ == CellType::stem) {
        if (!std::bernoulli_distribution(PROB_SYMMETRIC_DIVISION_)(wtl::sfmt())) {
            type_ = CellType::nonstem;
        }
    }
}

std::string Cell::mutate() {
    auto oss = wtl::make_oss();
    if (BERN_BIRTH(wtl::sfmt())) {
        double s = GAUSS_BIRTH(wtl::sfmt());
        oss << genealogy_.back() << "\tbirth\t" << s << "\n";
        birth_rate_ *= (s += 1.0);
    }
    if (BERN_DEATH(wtl::sfmt())) {
        double s = GAUSS_DEATH(wtl::sfmt());
        oss << genealogy_.back() << "\tdeath\t" << s << "\n";
        death_rate_ *= (s += 1.0);
        death_prob_ *= (s += 1.0);
    }
    if (BERN_MIGRA(wtl::sfmt())) {
        double s = GAUSS_MIGRA(wtl::sfmt());
        oss << genealogy_.back() << "\tmigra\t" << s << "\n";
        migra_rate_ *= (s += 1.0);
    }
    return oss.str();
}

std::string Cell::force_mutate() {
    birth_rate_ *= (1.0 + DRIVER_MEAN_BIRTH_);
    death_rate_ *= (1.0 + DRIVER_MEAN_DEATH_);
    death_prob_ *= (1.0 + DRIVER_MEAN_DEATH_);
    migra_rate_ *= (1.0 + DRIVER_MEAN_MIGRA_);
    const size_t id = genealogy_.back();
    auto oss = wtl::make_oss();
    oss << id << "\tbirth\t" << DRIVER_MEAN_BIRTH_ << "\n"
        << id << "\tdeath\t" << DRIVER_MEAN_DEATH_ << "\n"
        << id << "\tmigra\t" << DRIVER_MEAN_MIGRA_ << "\n";
    return oss.str();
}

double Cell::delta_time(const double positional_value) {
    double t_birth = std::numeric_limits<double>::infinity();
    double t_death = std::numeric_limits<double>::infinity();
    double t_migra = std::numeric_limits<double>::infinity();
    if (proliferation_capacity_ > 0) {
        double mu = 1.0;
        mu /= birth_rate_;
        mu /= positional_value;
        mu -= elapsed_;
        double theta = std::max(mu / GAMMA_SHAPE_, 0.0);
        std::gamma_distribution<double> gamma(GAMMA_SHAPE_, theta);
        t_birth = gamma(wtl::sfmt());
    }
    if (death_rate_ > 0.0) {
        std::exponential_distribution<double> exponential(death_rate_);
        t_death = exponential(wtl::sfmt());
    }
    if (migra_rate_ > 0.0) {
        std::exponential_distribution<double> exponential(migra_rate_);
        t_migra = exponential(wtl::sfmt());
    }

    if (t_birth < t_death && t_birth < t_migra) {
        std::bernoulli_distribution bern_death(death_prob_);
        if (bern_death(wtl::sfmt())) {
            next_event_ = Event::death;
        } else {
            next_event_ = Event::birth;
        }
        elapsed_ = 0.0;
        return t_birth;
    } else if (t_death < t_migra) {
        next_event_ = Event::death;
        return t_death;
    } else {
        next_event_ = Event::migration;
        elapsed_ += t_migra;
        return t_migra;
    }
}

std::vector<int> Cell::has_mutations_of(const std::vector<size_t>& mutants) {
    std::vector<int> genotype;
    genotype.reserve(mutants.size());
    for (const size_t mut: mutants) {
        if (std::find(genealogy_.begin(), genealogy_.end(), mut) != genealogy_.end()) {
            genotype.push_back(1);
        } else {
            genotype.push_back(0);
        }
    }
    return genotype;
}

size_t Cell::branch_length(const Cell& other) const {
    const size_t this_len = genealogy_.size();
    const size_t other_len = other.genealogy_.size();
    const size_t shorter = std::min(this_len, other_len);
    size_t branch = this_len + other_len;
    for (size_t i=0; i<shorter; ++i) {
        if (genealogy_[i] != other.genealogy_[i]) break;
        branch -= 2;
    }
    return branch;
}

std::string Cell::header(const char* sep) {
    std::ostringstream oss;
    oss << "x" << sep << "y" << sep << "z" << sep
        << "genealogy" << sep
        << "birth" << sep << "death" << sep
        << "beta" << sep << "delta" << sep << "alpha" << sep << "rho" << sep
        << "type" << sep << "omega";
    return oss.str();
}

std::ostream& Cell::write(std::ostream& ost, const char* sep) const {
    int z = 0;
    if (coord_.size() > 2) {z = coord_[2];}
    return ost
        << coord_[0] << sep << coord_[1] << sep << z << sep
        << wtl::join(genealogy_, ":") << sep
        << time_of_birth_ << sep << time_of_death_ << sep
        << birth_rate_ << sep
        << death_rate_ << sep << death_prob_ << sep
        << migra_rate_ << sep
        << static_cast<int>(type_) << sep <<
        proliferation_capacity_;
}

std::string Cell::str(const char* sep) const {
    auto oss = wtl::make_oss();
    write(oss, sep);
    return oss.str();
}

//! Stream operator for debug print
std::ostream& operator<< (std::ostream& ost, const Cell& x) {
    return x.write(ost, "\t");
}

void Cell::unit_test() {
    std::cerr << __PRETTY_FUNCTION__ << std::endl;
    std::cerr.precision(15);
    Cell cell({1, 2, 3});
    std::cerr << Cell::header("\t") << "\n" << cell << std::endl;
    std::exponential_distribution<double> exponential(0.0);
    std::cerr << "exponential(0): " << exponential(wtl::sfmt()) << std::endl;
}

} // namespace tumopp
<commit_msg>Inherit death_prob_ correctly: bug fix of 3ad5b7b583de80aff7f433e2b8929f3628dfea8d<commit_after>// -*- mode: c++; coding: utf-8 -*-
/*! @file cell.cpp
    @brief Implementation of Cell class
*/
#include "cell.hpp"

#include <iostream>
#include <sstream>

#include <boost/program_options.hpp>

#include <cxxwtils/prandom.hpp>
#include <cxxwtils/iostr.hpp>

namespace tumopp {

double Cell::BIRTH_RATE_;
double Cell::DEATH_RATE_;
double Cell::DEATH_PROB_;
double Cell::MIGRATION_RATE_;
double Cell::GAMMA_SHAPE_;
double Cell::PROB_SYMMETRIC_DIVISION_;
size_t Cell::MAX_PROLIFERATION_CAPACITY_;
double Cell::MUTATION_RATE_;
double Cell::DRIVER_RATE_BIRTH_;
double Cell::DRIVER_RATE_DEATH_;
double Cell::DRIVER_RATE_MIGRA_;
double Cell::DRIVER_MEAN_BIRTH_;
double Cell::DRIVER_MEAN_DEATH_;
double Cell::DRIVER_MEAN_MIGRA_;
double Cell::DRIVER_SD_BIRTH_;
double Cell::DRIVER_SD_DEATH_;
double Cell::DRIVER_SD_MIGRA_;

namespace {
    std::bernoulli_distribution BERN_BIRTH;
    std::bernoulli_distribution BERN_DEATH;
    std::bernoulli_distribution BERN_MIGRA;
    std::normal_distribution<double> GAUSS_BIRTH;
    std::normal_distribution<double> GAUSS_DEATH;
    std::normal_distribution<double> GAUSS_MIGRA;
}

//! Program options
/*! @return Program options description

    Command line option | Symbol              | Variable
    ------------------- | ------------------- | -------------------------
    `-b,--beta0`        | \f$\beta_0\f$       | Cell::BIRTH_RATE_
    `-d,--delta0`       | \f$\delta_0\f$      | Cell::DEATH_RATE_
    `-a,--alpha0`       | \f$\alpha_0\f$      | Cell::DEATH_PROB_
    `-m,--rho0`         | \f$\rho_0\f$        | Cell::MIGRATION_RATE_
    `-k,--shape`        | \f$k\f$             | Cell::GAMMA_SHAPE_
    `-p,--symmetric`    | \f$p_s\f$           | Cell::PROB_SYMMETRIC_DIVISION_
    `-r,--prolif`       | \f$\omega_{\max}\f$ | Cell::MAX_PROLIFERATION_CAPACITY_
    `-u,--mutation`     | \f$\mu\f$           | Cell::MUTATION_RATE_
    `--ub`              |                     | Cell::DRIVER_RATE_BIRTH_
    `--ud`              |                     | Cell::DRIVER_RATE_DEATH_
    `--um`              |                     | Cell::DRIVER_RATE_MIGRA_
    `--mb`              |                     | Cell::DRIVER_MEAN_BIRTH_
    `--md`              |                     | Cell::DRIVER_MEAN_DEATH_
    `--mm`              |                     | Cell::DRIVER_MEAN_MIGRA_
    `--sb`              |                     | Cell::DRIVER_SD_BIRTH_
    `--sd`              |                     | Cell::DRIVER_SD_DEATH_
    `--sm`              |                     | Cell::DRIVER_SD_MIGRA_
*/
boost::program_options::options_description Cell::opt_description() {
    namespace po = boost::program_options;
    po::options_description desc{"Cell"};
    desc.add_options()
        ("beta0,b", po::value(&BIRTH_RATE_)->default_value(1.0))
        ("delta0,d", po::value(&DEATH_RATE_)->default_value(0.0))
        ("alpha0,a", po::value(&DEATH_PROB_)->default_value(0.0))
        ("rho0,m", po::value(&MIGRATION_RATE_)->default_value(0.0))
        ("shape,k", po::value(&GAMMA_SHAPE_)->default_value(1.0))
        ("symmetric,p", po::value(&PROB_SYMMETRIC_DIVISION_)->default_value(1.0))
        ("prolif,r", po::value(&MAX_PROLIFERATION_CAPACITY_)->default_value(10))
        ("mutation,u", po::value(&MUTATION_RATE_)->default_value(1e-1))
        ("ub", po::value(&DRIVER_RATE_BIRTH_)->default_value(0.0))
        ("ud", po::value(&DRIVER_RATE_DEATH_)->default_value(0.0))
        ("um", po::value(&DRIVER_RATE_MIGRA_)->default_value(0.0))
        ("mb", po::value(&DRIVER_MEAN_BIRTH_)->default_value(0.0))
        ("md", po::value(&DRIVER_MEAN_DEATH_)->default_value(0.0))
        ("mm", po::value(&DRIVER_MEAN_MIGRA_)->default_value(0.0))
        ("sb", po::value(&DRIVER_SD_BIRTH_)->default_value(0.0))
        ("sd", po::value(&DRIVER_SD_DEATH_)->default_value(0.0))
        ("sm", po::value(&DRIVER_SD_MIGRA_)->default_value(0.0))
    ;
    return desc;
}

void Cell::init_distributions() {
    BERN_BIRTH = std::bernoulli_distribution(DRIVER_RATE_BIRTH_);
    BERN_DEATH = std::bernoulli_distribution(DRIVER_RATE_DEATH_);
    BERN_MIGRA = std::bernoulli_distribution(DRIVER_RATE_MIGRA_);
    GAUSS_BIRTH = std::normal_distribution<double>(DRIVER_MEAN_BIRTH_, DRIVER_SD_BIRTH_);
    GAUSS_DEATH = std::normal_distribution<double>(DRIVER_MEAN_DEATH_, DRIVER_SD_DEATH_);
    GAUSS_MIGRA = std::normal_distribution<double>(DRIVER_MEAN_MIGRA_, DRIVER_SD_MIGRA_);
}

Cell::Cell(const Cell& other):
    coord_(other.coord_),
    birth_rate_(other.birth_rate_),
    death_rate_(other.death_rate_),
    death_prob_(other.death_prob_),
    migra_rate_(other.migra_rate_),
    type_(other.type_),
    proliferation_capacity_(other.proliferation_capacity_),
    genealogy_(other.genealogy_) {
    if (type_ == CellType::stem) {
        if (!std::bernoulli_distribution(PROB_SYMMETRIC_DIVISION_)(wtl::sfmt())) {
            type_ = CellType::nonstem;
        }
    }
}

std::string Cell::mutate() {
    auto oss = wtl::make_oss();
    if (BERN_BIRTH(wtl::sfmt())) {
        double s = GAUSS_BIRTH(wtl::sfmt());
        oss << genealogy_.back() << "\tbirth\t" << s << "\n";
        birth_rate_ *= (s += 1.0);
    }
    if (BERN_DEATH(wtl::sfmt())) {
        double s = GAUSS_DEATH(wtl::sfmt());
        oss << genealogy_.back() << "\tdeath\t" << s << "\n";
        death_rate_ *= (s += 1.0);
        death_prob_ *= (s += 1.0);
    }
    if (BERN_MIGRA(wtl::sfmt())) {
        double s = GAUSS_MIGRA(wtl::sfmt());
        oss << genealogy_.back() << "\tmigra\t" << s << "\n";
        migra_rate_ *= (s += 1.0);
    }
    return oss.str();
}

std::string Cell::force_mutate() {
    birth_rate_ *= (1.0 + DRIVER_MEAN_BIRTH_);
    death_rate_ *= (1.0 + DRIVER_MEAN_DEATH_);
    death_prob_ *= (1.0 + DRIVER_MEAN_DEATH_);
    migra_rate_ *= (1.0 + DRIVER_MEAN_MIGRA_);
    const size_t id = genealogy_.back();
    auto oss = wtl::make_oss();
    oss << id << "\tbirth\t" << DRIVER_MEAN_BIRTH_ << "\n"
        << id << "\tdeath\t" << DRIVER_MEAN_DEATH_ << "\n"
        << id << "\tmigra\t" << DRIVER_MEAN_MIGRA_ << "\n";
    return oss.str();
}

double Cell::delta_time(const double positional_value) {
    double t_birth = std::numeric_limits<double>::infinity();
    double t_death = std::numeric_limits<double>::infinity();
    double t_migra = std::numeric_limits<double>::infinity();
    if (proliferation_capacity_ > 0) {
        double mu = 1.0;
        mu /= birth_rate_;
        mu /= positional_value;
        mu -= elapsed_;
        double theta = std::max(mu / GAMMA_SHAPE_, 0.0);
        std::gamma_distribution<double> gamma(GAMMA_SHAPE_, theta);
        t_birth = gamma(wtl::sfmt());
    }
    if (death_rate_ > 0.0) {
        std::exponential_distribution<double> exponential(death_rate_);
        t_death = exponential(wtl::sfmt());
    }
    if (migra_rate_ > 0.0) {
        std::exponential_distribution<double> exponential(migra_rate_);
        t_migra = exponential(wtl::sfmt());
    }

    if (t_birth < t_death && t_birth < t_migra) {
        std::bernoulli_distribution bern_death(death_prob_);
        if (bern_death(wtl::sfmt())) {
            next_event_ = Event::death;
        } else {
            next_event_ = Event::birth;
        }
        elapsed_ = 0.0;
        return t_birth;
    } else if (t_death < t_migra) {
        next_event_ = Event::death;
        return t_death;
    } else {
        next_event_ = Event::migration;
        elapsed_ += t_migra;
        return t_migra;
    }
}

std::vector<int> Cell::has_mutations_of(const std::vector<size_t>& mutants) {
    std::vector<int> genotype;
    genotype.reserve(mutants.size());
    for (const size_t mut: mutants) {
        if (std::find(genealogy_.begin(), genealogy_.end(), mut) != genealogy_.end()) {
            genotype.push_back(1);
        } else {
            genotype.push_back(0);
        }
    }
    return genotype;
}

size_t Cell::branch_length(const Cell& other) const {
    const size_t this_len = genealogy_.size();
    const size_t other_len = other.genealogy_.size();
    const size_t shorter = std::min(this_len, other_len);
    size_t branch = this_len + other_len;
    for (size_t i=0; i<shorter; ++i) {
        if (genealogy_[i] != other.genealogy_[i]) break;
        branch -= 2;
    }
    return branch;
}

std::string Cell::header(const char* sep) {
    std::ostringstream oss;
    oss << "x" << sep << "y" << sep << "z" << sep
        << "genealogy" << sep
        << "birth" << sep << "death" << sep
        << "beta" << sep << "delta" << sep << "alpha" << sep << "rho" << sep
        << "type" << sep << "omega";
    return oss.str();
}

std::ostream& Cell::write(std::ostream& ost, const char* sep) const {
    int z = 0;
    if (coord_.size() > 2) {z = coord_[2];}
    return ost
        << coord_[0] << sep << coord_[1] << sep << z << sep
        << wtl::join(genealogy_, ":") << sep
        << time_of_birth_ << sep << time_of_death_ << sep
        << birth_rate_ << sep
        << death_rate_ << sep << death_prob_ << sep
        << migra_rate_ << sep
        << static_cast<int>(type_) << sep <<
        proliferation_capacity_;
}

std::string Cell::str(const char* sep) const {
    auto oss = wtl::make_oss();
    write(oss, sep);
    return oss.str();
}

//! Stream operator for debug print
std::ostream& operator<< (std::ostream& ost, const Cell& x) {
    return x.write(ost, "\t");
}

void Cell::unit_test() {
    std::cerr << __PRETTY_FUNCTION__ << std::endl;
    std::cerr.precision(15);
    Cell cell({1, 2, 3});
    std::cerr << Cell::header("\t") << "\n" << cell << std::endl;
    std::exponential_distribution<double> exponential(0.0);
    std::cerr << "exponential(0): " << exponential(wtl::sfmt()) << std::endl;
}

} // namespace tumopp
<|endoftext|>


<commit_before>#include "cube.h"
#include "tools.h"
#include "camera.h"

uint32_t cube_t::buf_usage = 0;
mesh_t cube_t::mesh = {};
object_t::gdef_t cube_t::gfx = {};

void cube_t::setup(glm::vec3 pos) {
  this->pos = pos;
  if (!buf_usage++) {
    mesh_create_info_t mci = { .type = mesh_type::CUBE,
                               .sz_param0 = 0.5f, // length
                               .sz_param1 = 0.5f, // breadth
                               .sz_param2 = 0.5f  // depth
    };
    create_mesh_data(&mci, &mesh);
    this->init_static_bufs_(mesh, gfx);
  }
}

void cube_t::teardown(void) {
  if (--buf_usage == 0)
    this->destroy_static_bufs_(gfx);
}

void cube_t::update(float dt) {
  static float t = 0;
  t += dt;
  pos.y = sin(t) + 1.0f;
  mat = glm::translate(glm::mat4(1.0), pos);
}

void cube_t::render(GLuint shdr_prog) {
  assert(glIsProgram(shdr_prog) && "Invalid program handle!");
  glUseProgram(shdr_prog);

  glm::mat4 mvp = cam.get_proj() * cam.get_matrix() * get_matrix();
  GLint location = glGetUniformLocation(shdr_prog, "u_mvp");
  glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(mvp));

  glm::mat3 normal = glm::transpose(glm::inverse(glm::mat3(get_matrix())));
  location = glGetUniformLocation(shdr_prog, "u_norm_mtrx");
  glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(normal));

  glBindVertexArray(gfx.vao);
  glEnableVertexAttribArray(gdef_t::vattr::pos);
  glEnableVertexAttribArray(gdef_t::vattr::norm);

  glDrawElements(GL_TRIANGLES, mesh.idx_data.size(), GL_UNSIGNED_INT, NULL);

  glDisableVertexAttribArray(gdef_t::vattr::pos);
  glDisableVertexAttribArray(gdef_t::vattr::norm);
  glBindVertexArray(0);
  glUseProgram(0);
}

uint32_t sphere_t::buf_usage = 0;
mesh_t sphere_t::mesh = {};
object_t::gdef_t sphere_t::gfx = {};

void sphere_t::setup(glm::vec3 pos) {

  if (!buf_usage++) {
    mesh_create_info_t mci = { .type = mesh_type::SPHERE,
                               .sz_param0 = 2.0f,  // diameter
                               .sz_param1 = 32.0f, // lattitude
                               .sz_param2 = 32.0f  // longitude
    };

    create_mesh_data(&mci, &mesh);
    this->init_static_bufs_(mesh, gfx);
  }

  this->pos = pos;
  state.mass = 0.01f;
  state.force = { 0.0f, 0.0f, 0.0f };
  state.accl = { 0.0f, 0.0f, 0.0f };
  state.crnt_vel = { 0.0f, 0.0f, 0.0f };
  state.prev_vel = { 0.0f, 0.0f, 0.0f };
}

void sphere_t::teardown(void) {
  if (--buf_usage == 0)
    this->destroy_static_bufs_(gfx);
}

bool sphere_t::check_collisions(void) {
  float r = 1.0f; // radius

  // when a sphere is in contact with a plane L (the positive side)
  // The distance from the centre of the sphere P to the plane in the
  // length of the radius
  // L.P = r (writing L as a 4D vector L = <N, D>)
  // The relationship L.P can be written as:
  // N.P + D = r <=> N.P + (D-r) = 0
  // This is the same as saying point P lies on the plane L' given by:
  // L' = <N, D-r>
  // The plane L' is parallel to L
  float D = 0.0f;
  float plane_diff = glm::abs(D - r);
  glm::vec4 L(0.0f, 1.0f, 0.0f, D), L0 = glm::vec4(glm::vec3(L), plane_diff);

  // if L.P >= r then there is no colision
  bool colliding = (glm::dot(glm::vec3(L), pos) + plane_diff) < r;

  return colliding;
}

void sphere_t::update(float dt) {
  dt = glm::clamp(dt, 0.0f, 0.01f);

  const glm::vec3 fgrav = { 0.0f, -9.8f, 0.0f };
  const glm::vec3 fnorm = -fgrav;

  // sum forces
  state.force = fgrav;
  bool colliding = check_collisions();
  if (colliding)
    state.force += fnorm;

  state.accl = (state.force / state.mass);
  state.crnt_vel = (state.prev_vel + state.accl) * dt;
  pos += state.crnt_vel * dt;

  state.prev_vel = state.crnt_vel;
  mat = glm::translate(glm::mat4(1.0f), pos);
}

void sphere_t::render(GLuint shdr_prog) {
  assert(glIsProgram(shdr_prog) && "Invalid program handle!");
  glUseProgram(shdr_prog);

  glm::mat4 mvp = cam.get_proj() * cam.get_matrix() * get_matrix();
  GLint location = glGetUniformLocation(shdr_prog, "u_mvp");
  glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(mvp));

  glm::mat3 normal = glm::transpose(glm::inverse(glm::mat3(get_matrix())));
  location = glGetUniformLocation(shdr_prog, "u_norm_mtrx");
  glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(normal));

  glBindVertexArray(gfx.vao);
  glEnableVertexAttribArray(gdef_t::vattr::pos);
  // glEnableVertexAttribArray(gdef_t::vattr::norm);

  glDrawArrays(GL_LINE_LOOP, 0, mesh.vtx_data.size());

  glDisableVertexAttribArray(gdef_t::vattr::pos);
  // glDisableVertexAttribArray(gdef_t::vattr::norm);
  glBindVertexArray(0);
  glUseProgram(0);
}
<commit_msg>small change<commit_after>#include "cube.h"
#include "tools.h"
#include "camera.h"

uint32_t cube_t::buf_usage = 0;
mesh_t cube_t::mesh = {};
object_t::gdef_t cube_t::gfx = {};

void cube_t::setup(glm::vec3 pos) {
  this->pos = pos;
  if (!buf_usage++) {
    mesh_create_info_t mci = { .type = mesh_type::CUBE,
                               .sz_param0 = 0.5f, // length
                               .sz_param1 = 0.5f, // breadth
                               .sz_param2 = 0.5f  // depth
    };
    create_mesh_data(&mci, &mesh);
    this->init_static_bufs_(mesh, gfx);
  }
}

void cube_t::teardown(void) {
  if (--buf_usage == 0)
    this->destroy_static_bufs_(gfx);
}

void cube_t::update(float dt) {
  static float t = 0;
  t += dt;
  pos.y = sin(t) + 1.0f;
  mat = glm::translate(glm::mat4(1.0), pos);
}

void cube_t::render(GLuint shdr_prog) {
  assert(glIsProgram(shdr_prog) && "Invalid program handle!");
  glUseProgram(shdr_prog);

  glm::mat4 mvp = cam.get_proj() * cam.get_matrix() * get_matrix();
  GLint location = glGetUniformLocation(shdr_prog, "u_mvp");
  glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(mvp));

  glm::mat3 normal = glm::transpose(glm::inverse(glm::mat3(get_matrix())));
  location = glGetUniformLocation(shdr_prog, "u_norm_mtrx");
  glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(normal));

  glBindVertexArray(gfx.vao);
  glEnableVertexAttribArray(gdef_t::vattr::pos);
  glEnableVertexAttribArray(gdef_t::vattr::norm);

  glDrawElements(GL_TRIANGLES, mesh.idx_data.size(), GL_UNSIGNED_INT, NULL);

  glDisableVertexAttribArray(gdef_t::vattr::pos);
  glDisableVertexAttribArray(gdef_t::vattr::norm);
  glBindVertexArray(0);
  glUseProgram(0);
}

uint32_t sphere_t::buf_usage = 0;
mesh_t sphere_t::mesh = {};
object_t::gdef_t sphere_t::gfx = {};

void sphere_t::setup(glm::vec3 pos) {

  if (!buf_usage++) {
    mesh_create_info_t mci = { .type = mesh_type::SPHERE,
                               .sz_param0 = 2.0f,  // diameter
                               .sz_param1 = 32.0f, // lattitude
                               .sz_param2 = 32.0f  // longitude
    };

    create_mesh_data(&mci, &mesh);
    this->init_static_bufs_(mesh, gfx);
  }

  this->pos = pos;
  state.mass = 0.01f;
  state.force = { 0.0f, 0.0f, 0.0f };
  state.accl = { 0.0f, 0.0f, 0.0f };
  state.crnt_vel = { 0.0f, 0.0f, 0.0f };
  state.prev_vel = { 0.0f, 0.0f, 0.0f };
}

void sphere_t::teardown(void) {
  if (--buf_usage == 0)
    this->destroy_static_bufs_(gfx);
}

bool sphere_t::check_collisions(void) {
  float r = 1.0f; // radius

  // when a sphere is in contact with a plane L (the positive side)
  // The distance from the centre of the sphere P to the plane in the
  // length of the radius
  // L.P = r (writing L as a 4D vector L = <N, D>)
  // The relationship L.P can be written as:
  // N.P + D = r <=> N.P + (D-r) = 0
  // This is the same as saying point P lies on the plane L' given by:
  // L' = <N, D-r>
  // The plane L' is parallel to L
  float D = 0.0f;
  float plane_diff = (D - r);
  glm::vec4 L(0.0f, 1.0f, 0.0f, D), L0 = glm::vec4(glm::vec3(L), plane_diff);

  // if L.P >= r then there is no colision
  bool colliding = (glm::dot(glm::vec3(L), pos) + plane_diff) < r;

  return colliding;
}

void sphere_t::update(float dt) {
  dt = glm::clamp(dt, 0.0f, 0.01f);

  const glm::vec3 fgrav = { 0.0f, -9.8f, 0.0f };
  const glm::vec3 fnorm = -fgrav;

  glm::vec3 momentum = state.mass * state.crnt_vel;

  // sum forces
  state.force = fgrav;
  bool colliding = check_collisions();
  if (colliding)
    state.force += fnorm;

  state.accl = (state.force / state.mass);
  state.crnt_vel = (state.prev_vel + state.accl) * dt;
  pos += state.crnt_vel * dt;

  state.prev_vel = state.crnt_vel;
  mat = glm::translate(glm::mat4(1.0f), pos);
}

void sphere_t::render(GLuint shdr_prog) {
  assert(glIsProgram(shdr_prog) && "Invalid program handle!");
  glUseProgram(shdr_prog);

  glm::mat4 mvp = cam.get_proj() * cam.get_matrix() * get_matrix();
  GLint location = glGetUniformLocation(shdr_prog, "u_mvp");
  glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(mvp));

  glm::mat3 normal = glm::transpose(glm::inverse(glm::mat3(get_matrix())));
  location = glGetUniformLocation(shdr_prog, "u_norm_mtrx");
  glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(normal));

  glBindVertexArray(gfx.vao);
  glEnableVertexAttribArray(gdef_t::vattr::pos);
  // glEnableVertexAttribArray(gdef_t::vattr::norm);

  glDrawArrays(GL_LINE_LOOP, 0, mesh.vtx_data.size());

  glDisableVertexAttribArray(gdef_t::vattr::pos);
  // glDisableVertexAttribArray(gdef_t::vattr::norm);
  glBindVertexArray(0);
  glUseProgram(0);
}
<|endoftext|>


<commit_before>#include <string.h>
#include <node.h>
#include <nan.h>
#include <node_buffer.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/ecdh.h>

#include "eckey.h"

using namespace v8;
using namespace node;

// Not sure where this came from. but looks like a function that should be part of openssl
int static inline EC_KEY_regenerate_key(EC_KEY *eckey, const BIGNUM *priv_key) {
	if (!eckey) return 0;
	int ok = 0;
	BN_CTX *ctx = NULL;
	EC_POINT *pub_key = NULL;
	const EC_GROUP *group = EC_KEY_get0_group(eckey);
	if ((ctx = BN_CTX_new()) == NULL)
		goto err;
	pub_key = EC_POINT_new(group);
	if (pub_key == NULL)
		goto err;
	if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
		goto err;
	EC_KEY_set_private_key(eckey, priv_key);
	EC_KEY_set_public_key(eckey, pub_key);
	ok = 1;
err:
	if (pub_key)
		EC_POINT_free(pub_key);
	if (ctx != NULL)
		BN_CTX_free(ctx);
	return ok;
}

ECKey::ECKey(int curve) {
	mHasPrivateKey = false;
	mCurve = curve;
	mKey = EC_KEY_new_by_curve_name(mCurve);
	if (!mKey) {
		NanThrowError("EC_KEY_new_by_curve_name Invalid curve?");
		return;
	}
}
ECKey::~ECKey() {
	if (mKey) {
		EC_KEY_free(mKey);
	}
}

static Persistent<FunctionTemplate> constructor_template;

// Node module init
void ECKey::Init(Handle<Object> exports) {
	Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(New);
	tpl->SetClassName(NanNew<String>("ECKey"));
	tpl->InstanceTemplate()->SetInternalFieldCount(1);

	//Accessors
	tpl->InstanceTemplate()->SetAccessor(NanNew<String>("HasPrivateKey"), GetHasPrivateKey);
	tpl->InstanceTemplate()->SetAccessor(NanNew<String>("PublicKey"), GetPublicKey);
	tpl->InstanceTemplate()->SetAccessor(NanNew<String>("PrivateKey"), GetPrivateKey);

	//Methods (Prototype)
	tpl->PrototypeTemplate()->Set(NanNew<String>("sign"), NanNew<FunctionTemplate>(Sign)->GetFunction());
	tpl->PrototypeTemplate()->Set(NanNew<String>("verifySignature"), NanNew<FunctionTemplate>(VerifySignature)->GetFunction());
	tpl->PrototypeTemplate()->Set(NanNew<String>("deriveSharedSecret"), NanNew<FunctionTemplate>(DeriveSharedSecret)->GetFunction());

	NanAssignPersistent(constructor_template, tpl);
	exports->Set(NanNew<String>("ECKey"), tpl->GetFunction());
}

// Node constructor function
// new ECKey(curve, buffer, isPublic)
NAN_METHOD(ECKey::New) {
	if (!args.IsConstructCall()) {
		return NanThrowError("Must use new keyword");
	}
	if (args[0]->IsUndefined()) {
		return NanThrowError("First argument must be an ECCurve");
	}
	NanScope();
	ECKey *eckey = new ECKey(args[0]->NumberValue());
	if (!args[1]->IsUndefined()) {
		if (!Buffer::HasInstance(args[1])) {
			return NanThrowError("Second parameter must be a buffer");
		}
		//we have a second parameter, check the third to see if it is public or private.
		Handle<Object> buffer = args[1]->ToObject();
		const unsigned char *bufferData = (unsigned char *) Buffer::Data(buffer);
		if ((args[2]->IsUndefined()) || (args[2]->BooleanValue() == false)) {
			// it's a private key
			BIGNUM *bn = BN_bin2bn(bufferData, Buffer::Length(buffer), BN_new());
			if (EC_KEY_regenerate_key(eckey->mKey, bn) == 0) {
				BN_clear_free(bn);
				return NanThrowError("Invalid private key");
			}
			BN_clear_free(bn);
			eckey->mHasPrivateKey = true;
		} else {
			// it's a public key
			if (!o2i_ECPublicKey(&(eckey->mKey), &bufferData, Buffer::Length(buffer))) {
				return NanThrowError("o2i_ECPublicKey failed, Invalid public key");
			}
		}
	} else {
		if (!EC_KEY_generate_key(eckey->mKey)) {
			return NanThrowError("EC_KEY_generate_key failed");
		}
		eckey->mHasPrivateKey = true;
	}
	eckey->Wrap(args.Holder());
	NanReturnHolder();
}

static void FreeBufferData(char *data, void *hint) {
	free(data);
}

// Node properity functions
NAN_GETTER(ECKey::GetHasPrivateKey) {
	NanScope();
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	NanReturnValue(NanNew<Boolean>(eckey->mHasPrivateKey));
}
NAN_GETTER(ECKey::GetPublicKey) {
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	const EC_GROUP *group = EC_KEY_get0_group(eckey->mKey);
	const EC_POINT *point = EC_KEY_get0_public_key(eckey->mKey);
	unsigned int nReq = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL);
	if (!nReq) {
		return NanThrowError("EC_POINT_point2oct error");
	}
	unsigned char *buf, *buf2;
	buf = buf2 = (unsigned char *)malloc(nReq);
	if (EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, buf, nReq, NULL) != nReq) {
		return NanThrowError("EC_POINT_point2oct didn't return correct size");
	}
	NanScope();
	NanReturnValue(NanNewBufferHandle((char *)buf2, nReq, FreeBufferData, NULL));
}
NAN_GETTER(ECKey::GetPrivateKey) {
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	const BIGNUM *bn = EC_KEY_get0_private_key(eckey->mKey);
	if (bn == NULL) {
		return NanThrowError("EC_KEY_get0_private_key failed");
	}
	int priv_size = BN_num_bytes(bn);
	unsigned char *priv_buf = (unsigned char *)malloc(priv_size);
	int n = BN_bn2bin(bn, priv_buf);
	if (n != priv_size) {
		return NanThrowError("BN_bn2bin didn't return priv_size");
	}
	NanScope();
	NanReturnValue(NanNewBufferHandle((char *)priv_buf, priv_size, FreeBufferData, NULL));
}

// Node method functions
NAN_METHOD(ECKey::Sign) {
	NanScope();
	ECKey * eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	if (!Buffer::HasInstance(args[0])) {
		return NanThrowError("digest must be a buffer");
	}
	if (!eckey->mHasPrivateKey) {
		return NanThrowError("cannot sign without private key");
	}
	Handle<Object> digest = args[0]->ToObject();
	const unsigned char *digest_data = (unsigned char *)Buffer::Data(digest);
	unsigned int digest_len = Buffer::Length(digest);

	ECDSA_SIG *sig = ECDSA_do_sign(digest_data, digest_len, eckey->mKey);
	if (!sig) {
		return NanThrowError("ECDSA_do_sign");
	}
	int sig_len = i2d_ECDSA_SIG(sig, NULL);
	if (!sig_len) {
		return NanThrowError("i2d_ECDSA_SIG");
	}
	unsigned char *sig_data, *sig_data2;
	sig_data = sig_data2 = (unsigned char *)malloc(sig_len);
	if (i2d_ECDSA_SIG(sig, &sig_data) != sig_len) {
		ECDSA_SIG_free(sig);
		free(sig_data2);
		return NanThrowError("i2d_ECDSA_SIG didnot return correct length");
	}
	ECDSA_SIG_free(sig);
	NanReturnValue(NanNewBufferHandle((char *)sig_data2, sig_len, FreeBufferData, NULL));
}
NAN_METHOD(ECKey::VerifySignature) {
	NanScope();
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	if (!Buffer::HasInstance(args[0])) {
		return NanThrowError("digest must be a buffer");
	}
	if (!Buffer::HasInstance(args[1])) {
		return NanThrowError("signature must be a buffer");
	}
	Handle<Object> digest = args[0]->ToObject();
	Handle<Object> signature = args[1]->ToObject();
	const unsigned char *digest_data = (unsigned char *)Buffer::Data(digest);
	const unsigned char *signature_data = (unsigned char *)Buffer::Data(signature);
	unsigned int digest_len = Buffer::Length(digest);
	unsigned int signature_len = Buffer::Length(signature);
	int result = ECDSA_verify(0, digest_data, digest_len, signature_data, signature_len, eckey->mKey);
	if (result == -1) {
		return NanThrowError("ECDSA_verify");
	} else if (result == 0) {
		NanReturnValue(NanNew<Boolean>(false));
	} else if (result == 1) {
		NanReturnValue(NanNew<Boolean>(true));
	} else {
		return NanThrowError("ECDSA_verify gave an unexpected return value");
	}
}
NAN_METHOD(ECKey::DeriveSharedSecret) {
	NanScope();
	if (args[0]->IsUndefined()) {
		return NanThrowError("other is required");
	}
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	ECKey *other = ObjectWrap::Unwrap<ECKey>(args[0]->ToObject());
	if (!other) {
		return NanThrowError("other must be an ECKey");
	}
	unsigned char *secret = (unsigned char*)malloc(512);
	int len = ECDH_compute_key(secret, 512, EC_KEY_get0_public_key(other->mKey), eckey->mKey, NULL);
	NanReturnValue(NanNewBufferHandle((char *)secret, len, FreeBufferData, NULL));
}
<commit_msg>Switch to NODE_SET_PROTOTYPE_METHOD<commit_after>#include <string.h>
#include <node.h>
#include <nan.h>
#include <node_buffer.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/ecdh.h>

#include "eckey.h"

using namespace v8;
using namespace node;

// Not sure where this came from. but looks like a function that should be part of openssl
int static inline EC_KEY_regenerate_key(EC_KEY *eckey, const BIGNUM *priv_key) {
	if (!eckey) return 0;
	int ok = 0;
	BN_CTX *ctx = NULL;
	EC_POINT *pub_key = NULL;
	const EC_GROUP *group = EC_KEY_get0_group(eckey);
	if ((ctx = BN_CTX_new()) == NULL)
		goto err;
	pub_key = EC_POINT_new(group);
	if (pub_key == NULL)
		goto err;
	if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
		goto err;
	EC_KEY_set_private_key(eckey, priv_key);
	EC_KEY_set_public_key(eckey, pub_key);
	ok = 1;
err:
	if (pub_key)
		EC_POINT_free(pub_key);
	if (ctx != NULL)
		BN_CTX_free(ctx);
	return ok;
}

ECKey::ECKey(int curve) {
	mHasPrivateKey = false;
	mCurve = curve;
	mKey = EC_KEY_new_by_curve_name(mCurve);
	if (!mKey) {
		NanThrowError("EC_KEY_new_by_curve_name Invalid curve?");
		return;
	}
}
ECKey::~ECKey() {
	if (mKey) {
		EC_KEY_free(mKey);
	}
}

static Persistent<FunctionTemplate> constructor_template;

// Node module init
void ECKey::Init(Handle<Object> exports) {
	Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(New);
	tpl->SetClassName(NanNew<String>("ECKey"));
	tpl->InstanceTemplate()->SetInternalFieldCount(1);

	//Accessors
	tpl->InstanceTemplate()->SetAccessor(NanNew<String>("HasPrivateKey"), GetHasPrivateKey);
	tpl->InstanceTemplate()->SetAccessor(NanNew<String>("PublicKey"), GetPublicKey);
	tpl->InstanceTemplate()->SetAccessor(NanNew<String>("PrivateKey"), GetPrivateKey);

	//Methods (Prototype)
	NODE_SET_PROTOTYPE_METHOD(tpl, "sign", Sign);
	NODE_SET_PROTOTYPE_METHOD(tpl, "verifySignature", VerifySignature);
	NODE_SET_PROTOTYPE_METHOD(tpl, "deriveSharedSecret", DeriveSharedSecret);

	NanAssignPersistent(constructor_template, tpl);
	exports->Set(NanNew<String>("ECKey"), tpl->GetFunction());
}

// Node constructor function
// new ECKey(curve, buffer, isPublic)
NAN_METHOD(ECKey::New) {
	if (!args.IsConstructCall()) {
		return NanThrowError("Must use new keyword");
	}
	if (args[0]->IsUndefined()) {
		return NanThrowError("First argument must be an ECCurve");
	}
	NanScope();
	ECKey *eckey = new ECKey(args[0]->NumberValue());
	if (!args[1]->IsUndefined()) {
		if (!Buffer::HasInstance(args[1])) {
			return NanThrowError("Second parameter must be a buffer");
		}
		//we have a second parameter, check the third to see if it is public or private.
		Handle<Object> buffer = args[1]->ToObject();
		const unsigned char *bufferData = (unsigned char *) Buffer::Data(buffer);
		if ((args[2]->IsUndefined()) || (args[2]->BooleanValue() == false)) {
			// it's a private key
			BIGNUM *bn = BN_bin2bn(bufferData, Buffer::Length(buffer), BN_new());
			if (EC_KEY_regenerate_key(eckey->mKey, bn) == 0) {
				BN_clear_free(bn);
				return NanThrowError("Invalid private key");
			}
			BN_clear_free(bn);
			eckey->mHasPrivateKey = true;
		} else {
			// it's a public key
			if (!o2i_ECPublicKey(&(eckey->mKey), &bufferData, Buffer::Length(buffer))) {
				return NanThrowError("o2i_ECPublicKey failed, Invalid public key");
			}
		}
	} else {
		if (!EC_KEY_generate_key(eckey->mKey)) {
			return NanThrowError("EC_KEY_generate_key failed");
		}
		eckey->mHasPrivateKey = true;
	}
	eckey->Wrap(args.Holder());
	NanReturnHolder();
}

static void FreeBufferData(char *data, void *hint) {
	free(data);
}

// Node properity functions
NAN_GETTER(ECKey::GetHasPrivateKey) {
	NanScope();
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	NanReturnValue(NanNew<Boolean>(eckey->mHasPrivateKey));
}
NAN_GETTER(ECKey::GetPublicKey) {
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	const EC_GROUP *group = EC_KEY_get0_group(eckey->mKey);
	const EC_POINT *point = EC_KEY_get0_public_key(eckey->mKey);
	unsigned int nReq = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL);
	if (!nReq) {
		return NanThrowError("EC_POINT_point2oct error");
	}
	unsigned char *buf, *buf2;
	buf = buf2 = (unsigned char *)malloc(nReq);
	if (EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, buf, nReq, NULL) != nReq) {
		return NanThrowError("EC_POINT_point2oct didn't return correct size");
	}
	NanScope();
	NanReturnValue(NanNewBufferHandle((char *)buf2, nReq, FreeBufferData, NULL));
}
NAN_GETTER(ECKey::GetPrivateKey) {
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	const BIGNUM *bn = EC_KEY_get0_private_key(eckey->mKey);
	if (bn == NULL) {
		return NanThrowError("EC_KEY_get0_private_key failed");
	}
	int priv_size = BN_num_bytes(bn);
	unsigned char *priv_buf = (unsigned char *)malloc(priv_size);
	int n = BN_bn2bin(bn, priv_buf);
	if (n != priv_size) {
		return NanThrowError("BN_bn2bin didn't return priv_size");
	}
	NanScope();
	NanReturnValue(NanNewBufferHandle((char *)priv_buf, priv_size, FreeBufferData, NULL));
}

// Node method functions
NAN_METHOD(ECKey::Sign) {
	NanScope();
	ECKey * eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	if (!Buffer::HasInstance(args[0])) {
		return NanThrowError("digest must be a buffer");
	}
	if (!eckey->mHasPrivateKey) {
		return NanThrowError("cannot sign without private key");
	}
	Handle<Object> digest = args[0]->ToObject();
	const unsigned char *digest_data = (unsigned char *)Buffer::Data(digest);
	unsigned int digest_len = Buffer::Length(digest);

	ECDSA_SIG *sig = ECDSA_do_sign(digest_data, digest_len, eckey->mKey);
	if (!sig) {
		return NanThrowError("ECDSA_do_sign");
	}
	int sig_len = i2d_ECDSA_SIG(sig, NULL);
	if (!sig_len) {
		return NanThrowError("i2d_ECDSA_SIG");
	}
	unsigned char *sig_data, *sig_data2;
	sig_data = sig_data2 = (unsigned char *)malloc(sig_len);
	if (i2d_ECDSA_SIG(sig, &sig_data) != sig_len) {
		ECDSA_SIG_free(sig);
		free(sig_data2);
		return NanThrowError("i2d_ECDSA_SIG didnot return correct length");
	}
	ECDSA_SIG_free(sig);
	NanReturnValue(NanNewBufferHandle((char *)sig_data2, sig_len, FreeBufferData, NULL));
}
NAN_METHOD(ECKey::VerifySignature) {
	NanScope();
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	if (!Buffer::HasInstance(args[0])) {
		return NanThrowError("digest must be a buffer");
	}
	if (!Buffer::HasInstance(args[1])) {
		return NanThrowError("signature must be a buffer");
	}
	Handle<Object> digest = args[0]->ToObject();
	Handle<Object> signature = args[1]->ToObject();
	const unsigned char *digest_data = (unsigned char *)Buffer::Data(digest);
	const unsigned char *signature_data = (unsigned char *)Buffer::Data(signature);
	unsigned int digest_len = Buffer::Length(digest);
	unsigned int signature_len = Buffer::Length(signature);
	int result = ECDSA_verify(0, digest_data, digest_len, signature_data, signature_len, eckey->mKey);
	if (result == -1) {
		return NanThrowError("ECDSA_verify");
	} else if (result == 0) {
		NanReturnValue(NanNew<Boolean>(false));
	} else if (result == 1) {
		NanReturnValue(NanNew<Boolean>(true));
	} else {
		return NanThrowError("ECDSA_verify gave an unexpected return value");
	}
}
NAN_METHOD(ECKey::DeriveSharedSecret) {
	NanScope();
	if (args[0]->IsUndefined()) {
		return NanThrowError("other is required");
	}
	ECKey *eckey = ObjectWrap::Unwrap<ECKey>(args.Holder());
	ECKey *other = ObjectWrap::Unwrap<ECKey>(args[0]->ToObject());
	if (!other) {
		return NanThrowError("other must be an ECKey");
	}
	unsigned char *secret = (unsigned char*)malloc(512);
	int len = ECDH_compute_key(secret, 512, EC_KEY_get0_public_key(other->mKey), eckey->mKey, NULL);
	NanReturnValue(NanNewBufferHandle((char *)secret, len, FreeBufferData, NULL));
}
<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstring>
#include <fcntl.h>

using namespace std;
/* Broken - Fix later to help clean up code
void tokenize(char* arr[], char* token, string delims){
    unsigned cnt = 0;
    while(token != NULL){
	cout << "arr[" << cnt << "]: " << arr[cnt] << endl;
	arr[cnt] = token;
	token = strtok(NULL, delims);
	cnt++;
    }
    strcat(arr[cnt - 1], "\0");
    arr[cnt] = token;
    return;
}*/

int main(int argc, char* argv[]){
    string usrInput; //Holds user input
    while(1){
        cout << "$ "; //Prints prompt
	getline(cin, usrInput);
	char* inputCpy = new char[usrInput.length() + 1]; //pointer for input str
	strcpy(inputCpy, usrInput.c_str()); //inputCpy holds c-str copy of input
	unsigned cnt = 0; //counter for slots in argv[]
	//char buf[usrInput.length() + 1];
	char* token = strtok(inputCpy, ";"); //removes semicolons
	char* a[usrInput.length() + 1]; //Creates array for cmds + args
	while(token != NULL){ //Tokenizes semicolons
	    a[cnt] = token;
	    token = strtok(NULL, ";");
	    cnt++;
	}
	strcat(a[cnt - 1], "\0");
	a[cnt] = token; //Null terminates a[]

/*
	int x = 0;
	for(unsigned in = 0; in < cnt; in++){
	    cout << "a[" << in << "]: " << a[in] << endl;
	    x = in;
	}

//Old Fixme code - delete whenever checking for null in argv[] works
	cout << "Test:" << endl;
	cout << a[x+1] << endl;

	//cout << strcmp(a[x+1], "\0") << endl;
	cout << "......." << endl;
	return 0;
*/

	int curr = 0;
	for(int i = 0; i < cnt; i++){//Tokenizes a[] removing " "
	    token = strtok(a[i], " "); //Resets token
	    curr = 0;
	    while(token != NULL){ //Remove spaces
	        argv[curr] = token; //argv[] = a[] (without spaces)
		if(strcmp(argv[curr], "exit") == 0){//Exit check
		    cout << "Exiting..." << endl;
		    delete inputCpy;
		    exit(0);
		}
		//_____Operator Checks - IO Redirection_____
			//Note: curr - 1 is just the prior arg, you need to
			//couple it with the flags/command it's passed with
			//and redirect that OUTPUT to your output.txt
			//--------------------------------------------------
			//SOLUTION: Have an int "sym" that holds the position
			//of the last found symbol and then do a for loop
			//that combines all of the argv[]'s on one end
			//together and all of the other end together as well
			//and then update sym each time an operator is found
			//be sure to iterate it after the for loop concat, tho
		strcat(argv[curr], "\0"); //Null terms
		token = strtok(NULL, " ");
		curr++;
/*
	    	int x = 0; //Used for traversing
	   	int y = 0; //argv[]'s strings' chars
		int lastSym = 0; //char location of last symbol in an argv[] string
		while(strcmp(argv[x], "\0") != 0){//for each
		    while(argv[x][y] != '\0'){// char in argv[]
			if(argv[x][y] == '>'){//is Output
			    //if count + 1 == ">", then is Append
			    lastSym = y;
			}else if(argv[x][y] == '<'){//is Input
			    lastSym = y;
			}else if(argv[x][y] == '|'){//is Pipe
			    lastSym = y;
			}
			y++;//iterate through chars
		    }
		    //End of a string
		    if(y > 0){//if there is a symbol in argv[x]
			int pid2;
			if((pid2 = fork()) == -1){
			    perror("pid2() fork failed");
			    exit(1);
			}
		    }
		    x++;//iterate through strings
		    y = 0; //Resets y to beginning of string
		}
*/
	    }
	    strcpy(argv[curr], "\0");
	    //strcat(argv[curr], "\0"); //Null terms the last string
	    //argv[curr] = token; //Null terms array
	    int x = 0; //Used for traversing
	    int y = 0; //argv[]'s strings' chars
	    int lastSym = 0; //char location of last symbol in an argv[] string
	cout << "HALP" << endl;
		while(argv[x][0] != '\0'){//for each - FIXME - WHY THE HELL DOES THIS NOT TRIGGER?!
		    while(argv[x][y] != '\0'){// char in argv[]
			if(argv[x][y] == '>'){//is Output
			    //if count + 1 == ">", then is Append
			    lastSym = y;
			}else if(argv[x][y] == '<'){//is Input
			    lastSym = y;
			}else if(argv[x][y] == '|'){//is Pipe
			    lastSym = y;
			}
			cout << "char" << y << ": " << argv[x][y] << endl;
			y++;//iterate through chars
		    }
		    cout << "string" << x << ": " << argv[x] << endl;
		    cout << "strcmp-argv[" << x++ << "]: " << strcmp(argv[x], "\0") << endl;
		    //End of a string
		    /*if(y > 0){//if there is a symbol in argv[x]
			int pid2;
			if((pid2 = fork()) == -1){
			    perror("pid2() fork failed");
			    exit(1);
			}

		    }*/
		    x++;//iterate through strings
		    y = 0; //Resets y to beginning of string
		}
		cout << "Final argv[" << x << "]: " << argv[x] << endl;

	    //strcat(argv[curr], "\0"); //Null terms the last string
	    //argv[curr] = token; //Null terms array
	    //for(int z = 0; z < curr; z++){
	//	cout << "argv[" << z << "]: " << argv[z] << endl;
	  //  }

	    int pid = fork();
	    if(pid == -1){
		perror("pid fork  failed");
		exit(1);
	    }
	    if(pid == 0){ //Child process
		if(execvp(argv[0], argv) == -1){//Runs on each argv[]
		    perror("execvp() failed");
		    exit(1);
		}
	    }
	    //Parent function
	    if(-1 == wait(0)){ //waits on children - execs in order
		perror("wait() failed");
		exit(1);
	    }
	}
        delete inputCpy; //Deallocates memory - Fixme, might go elsewhere
    }//End while loop

    return 0;
}
<commit_msg>Working through errors<commit_after>#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstring>
#include <fcntl.h>

using namespace std;
/* Broken - Fix later to help clean up code
void tokenize(char* arr[], char* token, string delims){
    unsigned cnt = 0;
    while(token != NULL){
	cout << "arr[" << cnt << "]: " << arr[cnt] << endl;
	arr[cnt] = token;
	token = strtok(NULL, delims);
	cnt++;
    }
    strcat(arr[cnt - 1], "\0");
    arr[cnt] = token;
    return;
}*/

int main(int argc, char* argv[]){
    string usrInput; //Holds user input
    while(1){
        cout << "$ "; //Prints prompt
	getline(cin, usrInput);
	char* inputCpy = new char[usrInput.length() + 1]; //pointer for input str
	strcpy(inputCpy, usrInput.c_str()); //inputCpy holds c-str copy of input
	unsigned cnt = 0; //counter for slots in argv[]
	//char buf[usrInput.length() + 1];
	char* token = strtok(inputCpy, ";"); //removes semicolons
	char* a[usrInput.length() + 1]; //Creates array for cmds + args
	while(token != NULL){ //Tokenizes semicolons
	    a[cnt] = token;
	    token = strtok(NULL, ";");
	    cnt++;
	}
	strcat(a[cnt - 1], "\0");
	a[cnt] = token; //Null terminates a[]

	int curr = 0;
	for(int i = 0; i < cnt; i++){//Tokenizes a[] removing " "
	    token = strtok(a[i], " "); //Resets token
	    curr = 0;
	    while(token != NULL){ //Remove spaces
	        argv[curr] = token; //argv[] = a[] (without spaces)
		if(strcmp(argv[curr], "exit") == 0){//Exit check
		    cout << "Exiting..." << endl;
		    delete inputCpy;
		    exit(0);
		}
		strcat(argv[curr], "\0"); //Null terms
		token = strtok(NULL, " ");
		curr++;
	    }
	//}
	    //strcat(argv[curr], "\0"); //Null terms the last string
	    argv[curr] = token; //Null terms array
	    if(argv[curr] == NULL){
		cout << "Aight then. " << endl;
	    }
/*
	    int x = 0; //Used for traversing
	    int y = 0; //argv[]'s strings' chars
	    int lastSym = 0; //char location of last symbol in an argv[] string
	    while(argv[x] != NULL){//for each - FIXME - WHY THE HELL DOES THIS NOT TRIGGER?!
		while(argv[x][y] != '\0'){// char in argv[]
		    if(argv[x][y] == '>'){//is Output
			//if count + 1 == ">", then is Append
			lastSym = y;
		    }else if(argv[x][y] == '<'){//is Input
			lastSym = y;
		    }else if(argv[x][y] == '|'){//is Pipe
			lastSym = y;
		    }
		    //cout << "char" << y << ": " << argv[x][y] << endl;
		    y++;//iterate through chars
		}
		cout << "string" << x << ": " << argv[x] << endl;
		//cout << "strcmp-argv[" << x++ << "]: " << strcmp(argv[x], "\0") << endl;
		//End of a string
		x++;//iterate through strings
		y = 0; //Resets y to beginning of string
	    }
	    cout << "Final argv[" << x << "]: " << argv[x] << endl;

	    //strcat(argv[curr], "\0"); //Null terms the last string
	    //argv[curr] = token; //Null terms array

*/
	    int pid = fork();
	    if(pid == -1){
		perror("pid fork  failed");
		exit(1);
	    }
	    if(pid == 0){ //Child process
		if(execvp(argv[0], argv) == -1){//Runs on each argv[]
		    perror("execvp() failed");
		    exit(1);
		}
	    }
	    //Parent function
	    if(-1 == wait(0)){ //waits on children - execs in order
		perror("wait() failed");
		exit(1);
	    }
        delete inputCpy; //Deallocates memory - Fixme, might go elsewhere
    }//End while loop

    return 0;
}
<|endoftext|>


<commit_before>// Maintainer: Jan Kristian Sto. Domingo [jstod001@ucr.edu]
// exec.cpp for rshell

#include <iostream>
#include <cstring>
#include <string>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

//Notes on function formats:
//execvp(const char *file, char *const argv[])

// tokenCounter function used to determine size of dynamically
// allocated array for use in the execvp function
unsigned tokenCounter(char* a)
{
    unsigned count = 0;
    char* token;

    token = strtok(a, " ;");

    while(token != NULL)
    {
        token = strtok(NULL, " ;");
        count++;
    }

    return count;
}

int main()
{
    string str_input = "";
    do
    {
        cout << "\t<child process>" << endl;

        // command prompt
        char* username = getlogin();
        char hostname[20];
        gethostname(hostname, 20);
        cout << username << "@" << hostname << "$ ";

        str_input = "";
        getline(cin, str_input);

        // output message for test purposes
        // cout << "Original string: " << str_input << endl << endl;

        char* c_input = new char[str_input.length() + 1];
        strcpy(c_input, str_input.c_str());

        // output message for test purposes
        // cout << "Converted to cstring: " << c_input << endl << endl;

        // new cstring now has to be tokenized and placed into a char**
        // for the exec vp function

        char* tmp = new char[str_input.length() + 1];
        strcpy(tmp, c_input);
        // tmp protects the original cstring input
        // tmp will be used for the tokenCounter function

        unsigned token_count = 0;
        token_count = tokenCounter(tmp);

        char** arg;
        arg = new char* [token_count];

        // output message for test purposes
        // cout << "c_input after tokenCounter: " << c_input << endl;

        // the following chunk of code will take each token
        // and place it into arg which will then be used as
        // a parameter in execvp
        unsigned i = 0;
        char* ptr;
        ptr = strtok(c_input, " ;");
        while(ptr != NULL)
        {
            arg[i] = ptr;
            // cout message for test purposes
            //cout << "arg[" << i << "] = " << arg[i] << endl;
            ptr = strtok(NULL, " ;");
            i++;
        }

        //cout << arg[0] << endl;
        if(string(arg[0]) == "exit")
        {
            //cout message for test purposes
            cout << "\t<executing exit(0>)" << endl;
            exit(0);
        }

        int PID = fork();
        if(PID == 0)
        {
            //cout message for test purposes
            cout << "\t<in execvp>" << endl;
            execvp(arg[0], arg);
            perror(arg[0]);
        }
        else
        {
            if(PID == -1)
            {
                perror("fork");
            }
            int w = wait(0);
            if(w == -1)
            {
                perror("wait");
            }
            cout << "\t<parent process>" << endl;
        }

    }while(str_input != "exit");
/*
    else
    {
        if(PID == -1)
        {
            perror("fork");
        }
        int w = wait(0);
        if(w == -1)
        {
            perror("wait");
        }
        //cout << "parent process" << endl;
    }
*/
    return 0;
}

<commit_msg>fixed issue with echo not printing out more than one word<commit_after>// Maintainer: Jan Kristian Sto. Domingo [jstod001@ucr.edu]
// exec.cpp for rshell

#include <iostream>
#include <cstring>
#include <string>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

//Notes on function formats:
//execvp(const char *file, char *const argv[])

// tokenCounter function used to determine size of dynamically
// allocated array for use in the execvp function
unsigned tokenCounter(char* a)
{
    unsigned count = 0;
    char* token;

    token = strtok(a, " ;");

    while(token != NULL)
    {
        token = strtok(NULL, " ;");
        count++;
    }

    return count;
}

int main()
{
    string str_input = "";
    do
    {
        cout << "\t<child process>" << endl;

        // command prompt
        char* username = getlogin();
        char hostname[20];
        gethostname(hostname, 20);
        cout << username << "@" << hostname << "$ ";

        getline(cin, str_input);

        // output message for test purposes
        // cout << "Original string: " << str_input << endl << endl;

        char* c_input = new char[str_input.length() + 1];
        strcpy(c_input, str_input.c_str());

        // output message for test purposes
        // cout << "Converted to cstring: " << c_input << endl << endl;

        // new cstring now has to be tokenized and placed into a char**
        // for the exec vp function

        char* tmp = new char[str_input.length() + 1];
        strcpy(tmp, c_input);
        // tmp protects the original cstring input
        // tmp will be used for the tokenCounter function

        unsigned token_count = 0;
        token_count = tokenCounter(tmp);

        char** arg;
        arg = new char* [token_count + 1];

        // output message for test purposes
        // cout << "c_input after tokenCounter: " << c_input << endl;

        // the following chunk of code will take each token
        // and place it into arg which will then be used as
        // a parameter in execvp
        unsigned i = 0;
        char* ptr;
        ptr = strtok(c_input, " ;");
        while(ptr != NULL)
        {
            arg[i] = ptr;
            // cout message for test purposes
            // cout << "arg[" << i << "] = " << arg[i] << endl;
            // cout << "arg[" << i << "] length = " << strlen(arg[i]) << endl;
            ptr = strtok(NULL, " ;");
            i++;
        }
        arg[i] = '\0';

        //cout << arg[0] << endl;
        if(string(arg[0]) == "exit")
        {
            //cout message for test purposes
            cout << "\t<executing exit(0)>" << endl;
            exit(0);
        }

        int PID = fork();
        if(PID == 0)
        {
            //cout message for test purposes
            cout << "\t<in execvp>" << endl;
            execvp(arg[0], arg);
            perror(arg[0]);
        }
        else
        {
            if(PID == -1)
            {
                perror("fork failed");
            }
            int w = wait(0);
            if(w == -1)
            {
                perror("wait");
            }

            cout << "\t<parent process>" << endl;
        }
    }while(str_input != "exit");
/*
    else
    {
        if(PID == -1)
        {
            perror("fork");
        }
        int w = wait(0);
        if(w == -1)
        {
            perror("wait");
        }
        //cout << "parent process" << endl;
    }
*/
    return 0;
}

<|endoftext|>


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

#define PRINT false

// Pins in use
/**
 *  00 RX1 ..(CP2102)
 *  01 TX1 ..
 *  02                        * 23 ENC_B - Rotary B
 *  03                        * 22 ENC_A - Rotary A
 *  04                        * 21 Potentiometer
 *  05                        * 20 PWM - TFT:LITE <grey?>
 *  06 ENC_BTN <orange>       * 19 LED_GREEN <purple> 330ohm
 *  07 RX3 MTS <green>        * 18 LED_RED   <blue>   220ohm
 *  08 TX3 MTS <yellow>       * 17 TFT:RS  <blue>   D/C
 *  09 RX2 .. (GPS)           * 16 TFT:RST <green>  RST
 *  10 TX2 .. (GPS)           * 15 SPI:CS  <yellow> TCS
 *  11 SPI:DOUT <orange> SI   * 14 SPI:SCK <grey?>  SCK
 *  12 SPI:DIN  <red>    SO   * 13 LED_BOARD
 *
 *  [[ underside  ]]
 *
 *  ** not used **
 */
//

// UART Serial communications

// Host comms for data exchange with computer

//#define HWSERIAL      Serial2
//#define HWSERIAL_BAUD 57600

// GPS updates

//#define GPSSERIAL      Serial2
//#define GPSSERIAL_BAUD ???

// Innovate MTS serial data
#include <Drive.h>
#define MTSSERIAL      Serial2

#define RECBUFF 64
byte mtsbuffer[RECBUFF];

// Keep a small buffer for reading bytes from MTSSERIAL
void maintainMTS(); // Feed available serial data to Drive packet buffer

Drive drive;
void maintainDrive(); // Detect newly arrived packets

#include <ADC.h>
// https://forum.pjrc.com/threads/25532-ADC-library-update-now-with-support-for-Teensy-3-1
#include "RingBuffer.h"
// and IntervalTimer
#include <IntervalTimer.h>

#define ADC_RESOLUTION 12
#define ADC_POT A7 // (21) ADC0_SE7B

ADC *adc = new ADC();
IntervalTimer timer0;
RingBuffer *buffer0 = new RingBuffer;
int startTimerValue0 = 0;
const int period0 = 1000; // us

void setupADC();
void timer0_callback();

// LED Arrangement
#include <Led.h>

Led *Leds; // = {13, 18, 19};
const int LED_BOARD = 0; // Pin 13 (on board)
const int LED_GREEN = 1; // 18 <purple> GREEN
const int LED_RED = 2; // 19 <blue> RED
int ledCount;

void maintainLeds();
void setupLeds();

#define TFT_LITE   20 // PWM backlight/brightness control

Display display = Display();

#include <Encoder.h>

// Encoder
#define ENC_A      22
#define ENC_B      23
#define ENC_BUTTON 06

// Note the 2000millis delay during constructor!
Encoder rotary(ENC_A, ENC_B);

void maintainRotary();

#include <Bounce2.h>
//#include <algorithm>

Bounce debouncer = Bounce();

void setupButton();
void maintainButton();

#define ANSI_ESCAPE 0x1B
#define ANSI_LEFT_BRACKET 0x5B
const uint8_t ERASE_DISPLAY[] = {ANSI_ESCAPE, ANSI_LEFT_BRACKET, '2', 'J'};

void setup() {
    setupLeds();
    setupButton();
    setupADC();
    display.setupVolts(buffer0, adc->getMaxValue(0));

    // Indicate startup with all Leds
    Leds[LED_BOARD].flash(9999);
    Leds[LED_RED].flash(9999);
    Leds[LED_GREEN].flash(10);

    Serial.begin(19200);  // USB, communication to PC or Mac

    display.setupBrightness(TFT_LITE);
    display.setupChannel(0, 8191); // Lambda
    display.setupChannel(1, MTS10BIT_MAX); // AFM; up to ~4V
    display.setupChannel(2, 480); // O2; up to ~1.2V
    display.setupChannel(3, MTS10BIT_MAX);
//    display.setupChannel(4, MTS10BIT_MAX);

    // Waits until USB is connected
#if PRINT
    while(!Serial) {
        maintainLeds();
        delay(20);
    }
#endif // PRINT

    display.splash();

#if PRINT
    Serial.write(ERASE_DISPLAY, 4);

    Serial.println("Connected USB.");
#endif // PRINT

    MTSSERIAL.begin(MTSSERIAL_BAUD);
    while(!MTSSERIAL) {
        maintainLeds();
        delay(20);
    }
#if PRINT
    Serial.println("Connected MTS.");
#endif
    Leds[LED_BOARD].off();
    Leds[LED_RED].off();
    Leds[LED_GREEN].off();
}

/**
 * Configure the Leds[] collection
 */
void setupLeds() {
    int pins[3] = {13, 18, 19};
    Leds = Led::forPins(pins);
    ledCount = sizeof(Leds);
}

/**
 * Configure debuouncer.
 * - 10 millis of debounce
 */
void setupButton() {
    // Pullup requires the button connect the pin to ground
    debouncer.attach(ENC_BUTTON, INPUT_PULLUP);
    debouncer.interval(10);
}

/**
 * Configure analog input.
 * - Use a timer to do DMA reads to a buffer
 */
void setupADC() {
    pinMode(ADC_POT, INPUT);
    adc->setReference(ADC_REF_3V3, ADC_0);
    adc->setAveraging(16);
    adc->setResolution(ADC_RESOLUTION);
    adc->setConversionSpeed(ADC_MED_SPEED);
    adc->setSamplingSpeed(ADC_MED_SPEED);
    startTimerValue0 = timer0.begin(timer0_callback, period0);
    delayMicroseconds(250);
    adc->enableInterrupts(ADC_0);
}

// This function will be called with the desired frequency
// start the measurement
void timer0_callback(void) {
    adc->startSingleRead(ADC_POT, ADC_0); // also: startSingleDifferential, analogSynchronizedRead, analogSynchronizedReadDifferential
}

// when the measurement finishes, this will be called
// first: see which pin finished and then save the measurement into the correct buffer
void adc0_isr() {

    uint8_t pin = ADC::sc1a2channelADC0[ADC0_SC1A&ADC_SC1A_CHANNELS]; // the bits 0-4 of ADC0_SC1A have the channel

    // add value to correct buffer
    if(pin==ADC_POT) {
        buffer0->write(adc->readSingle());
        display.voltsReady(true);
    } else { // clear interrupt anyway
        adc->readSingle();
    }

    // restore ADC config if it was in use before being interrupted by the analog timer
    if (adc->adc0->adcWasInUse) {
        // restore ADC config, and restart conversion
        adc->adc0->loadConfig(&adc->adc0->adc_config);
        // avoid a conversion started by this isr to repeat itself
        adc->adc0->adcWasInUse = (uint8_t) false;
    }
}

/******* LOOP *******/

uint32_t lastLoop = millis();
void loop() {
    uint32_t now = millis();
    if (now - lastLoop > 10) {
        maintainMTS();
        maintainDrive();
        lastLoop = now;
    }
    maintainLeds();
    maintainRotary();
    maintainButton();
    display.maintain();
}

int32_t previousValue;

void maintainRotary() {
    int32_t value;
    value = rotary.read();
    if (value != previousValue) {
        int16_t delta = (int16_t) (previousValue - value);
        display.directionInput(delta);
        previousValue = value;
    }
}

bool wasPressed = false;
void maintainButton() {

    // Update the Bounce instance :
    debouncer.update();

    // Get the updated value :
    bool pressed = !debouncer.read();
    if (wasPressed != pressed) {
        display.pressInput(1, pressed);
        wasPressed = pressed;
        if (pressed) {
            Leds[LED_GREEN].on();
        } else {
            Leds[LED_GREEN].off();
        }
    }
}

// Each Led needs a `tick` to flash behaviour maintenance
void maintainLeds() {
    for (int i = 0; i < ledCount; i++) {
        Leds[i].tick();
    }
}

// When a new packet has been found, push parts of it into the display
// TODO: feed values into drive statistics (avg/min/max/etc)
void maintainDrive() {
    while(Packet *p = drive.nextPacket()) {
        // Process the packet by sending it's values to display for processing
        display.setChannel(0, p->lambda);
        if (p->channelCount >= 2) {
            display.setChannel(1, p->channel[1]);
            display.setChannel(2, p->channel[2]);
            display.setChannel(3, p->channel[3]);
//            display.setChannel(4, p->channel[4]);
        }
    }
    display.setElapsed(drive.elapsedMillis());
}

void maintainMTS() {
//    Leds[LED_BOARD].on();
    // TODO: Move serial input to interrupt timer
    int incomingAvailable = MTSSERIAL.available();
    if (incomingAvailable > 0) {
        Leds[LED_BOARD].on();
        uint8_t incomingRead = (uint8_t) MTSSERIAL.readBytes((char *) mtsbuffer, (size_t) incomingAvailable);
        if (incomingRead > 0) {
            // hand over bytes to packet buffer
            drive.addBytes((char *) mtsbuffer, incomingRead);
        }
        Leds[LED_BOARD].off();
    }
}<commit_msg>ADC Read Less Often<commit_after>#include <Arduino.h>
#include <Display.h>

#define PRINT false

// Pins in use
/**
 *  00 RX1 ..(CP2102)
 *  01 TX1 ..
 *  02                        * 23 ENC_B - Rotary B
 *  03                        * 22 ENC_A - Rotary A
 *  04                        * 21 Potentiometer
 *  05                        * 20 PWM - TFT:LITE <grey?>
 *  06 ENC_BTN <orange>       * 19 LED_GREEN <purple> 330ohm
 *  07 RX3 MTS <green>        * 18 LED_RED   <blue>   220ohm
 *  08 TX3 MTS <yellow>       * 17 TFT:RS  <blue>   D/C
 *  09 RX2 .. (GPS)           * 16 TFT:RST <green>  RST
 *  10 TX2 .. (GPS)           * 15 SPI:CS  <yellow> TCS
 *  11 SPI:DOUT <orange> SI   * 14 SPI:SCK <grey?>  SCK
 *  12 SPI:DIN  <red>    SO   * 13 LED_BOARD
 *
 *  [[ underside  ]]
 *
 *  ** not used **
 */
//

// UART Serial communications

// Host comms for data exchange with computer

//#define HWSERIAL      Serial2
//#define HWSERIAL_BAUD 57600

// GPS updates

//#define GPSSERIAL      Serial2
//#define GPSSERIAL_BAUD ???

// Innovate MTS serial data
#include <Drive.h>
#define MTSSERIAL      Serial2

#define RECBUFF 64
byte mtsbuffer[RECBUFF];

// Keep a small buffer for reading bytes from MTSSERIAL
void maintainMTS(); // Feed available serial data to Drive packet buffer

Drive drive;
void maintainDrive(); // Detect newly arrived packets

#include <ADC.h>
// https://forum.pjrc.com/threads/25532-ADC-library-update-now-with-support-for-Teensy-3-1
#include "RingBuffer.h"
// and IntervalTimer
#include <IntervalTimer.h>

#define ADC_RESOLUTION 12
#define ADC_POT A7 // (21) ADC0_SE7B

ADC *adc = new ADC();
IntervalTimer timer0;
RingBuffer *buffer0 = new RingBuffer;
int startTimerValue0 = 0;
const int period0 = 10000; // us
// 50,000 is good for infrequent signals

void setupADC();
void timer0_callback();

// LED Arrangement
#include <Led.h>

Led *Leds; // = {13, 18, 19};
const int LED_BOARD = 0; // Pin 13 (on board)
const int LED_GREEN = 1; // 18 <purple> GREEN
const int LED_RED = 2; // 19 <blue> RED
int ledCount;

void maintainLeds();
void setupLeds();

#define TFT_LITE   20 // PWM backlight/brightness control

Display display = Display();

#include <Encoder.h>

// Encoder
#define ENC_A      22
#define ENC_B      23
#define ENC_BUTTON 06

// Note the 2000millis delay during constructor!
Encoder rotary(ENC_A, ENC_B);

void maintainRotary();

#include <Bounce2.h>
//#include <algorithm>

Bounce debouncer = Bounce();

void setupButton();
void maintainButton();

#define ANSI_ESCAPE 0x1B
#define ANSI_LEFT_BRACKET 0x5B
const uint8_t ERASE_DISPLAY[] = {ANSI_ESCAPE, ANSI_LEFT_BRACKET, '2', 'J'};

void setup() {
    setupLeds();
    setupButton();
    setupADC();
    display.setupVolts(buffer0, adc->getMaxValue(0));

    // Indicate startup with all Leds
    Leds[LED_BOARD].flash(9999);
    Leds[LED_RED].flash(9999);
    Leds[LED_GREEN].flash(10);

    Serial.begin(19200);  // USB, communication to PC or Mac

    display.setupBrightness(TFT_LITE);
    display.setupChannel(0, 8191); // Lambda
    display.setupChannel(1, MTS10BIT_MAX); // AFM; up to ~4V
    display.setupChannel(2, 480); // O2; up to ~1.2V
    display.setupChannel(3, MTS10BIT_MAX);
//    display.setupChannel(4, MTS10BIT_MAX);

    // Waits until USB is connected
#if PRINT
    while(!Serial) {
        maintainLeds();
        delay(20);
    }
#endif // PRINT

    display.splash();

#if PRINT
    Serial.write(ERASE_DISPLAY, 4);

    Serial.println("Connected USB.");
#endif // PRINT

    MTSSERIAL.begin(MTSSERIAL_BAUD);
    while(!MTSSERIAL) {
        maintainLeds();
        delay(20);
    }
#if PRINT
    Serial.println("Connected MTS.");
#endif
    Leds[LED_BOARD].off();
    Leds[LED_RED].off();
    Leds[LED_GREEN].off();
}

/**
 * Configure the Leds[] collection
 */
void setupLeds() {
    int pins[3] = {13, 18, 19};
    Leds = Led::forPins(pins);
    ledCount = sizeof(Leds);
}

/**
 * Configure debuouncer.
 * - 10 millis of debounce
 */
void setupButton() {
    // Pullup requires the button connect the pin to ground
    debouncer.attach(ENC_BUTTON, INPUT_PULLUP);
    debouncer.interval(10);
}

/**
 * Configure analog input.
 * - Use a timer to do DMA reads to a buffer
 */
void setupADC() {
    pinMode(ADC_POT, INPUT);
    adc->setReference(ADC_REF_3V3, ADC_0);
    adc->setAveraging(16);
    adc->setResolution(ADC_RESOLUTION);
    adc->setConversionSpeed(ADC_MED_SPEED);
    adc->setSamplingSpeed(ADC_MED_SPEED);
    startTimerValue0 = timer0.begin(timer0_callback, period0);
    delayMicroseconds(250);
    adc->enableInterrupts(ADC_0);
}

// This function will be called with the desired frequency
// start the measurement
void timer0_callback(void) {
    adc->startSingleRead(ADC_POT, ADC_0); // also: startSingleDifferential, analogSynchronizedRead, analogSynchronizedReadDifferential
}

// when the measurement finishes, this will be called
// first: see which pin finished and then save the measurement into the correct buffer
//uint8_t isrTick = 0;
void adc0_isr() {
//    if (isrTick++ % 2) {
//        Leds[LED_GREEN].on();
//    } else {
//        Leds[LED_GREEN].off();
//    }

    uint8_t pin = ADC::sc1a2channelADC0[ADC0_SC1A&ADC_SC1A_CHANNELS]; // the bits 0-4 of ADC0_SC1A have the channel

    // add value to correct buffer
    if(pin==ADC_POT) {
        buffer0->write(adc->readSingle());
        display.voltsReady(true);
    } else { // clear interrupt anyway
        adc->readSingle();
    }

    // restore ADC config if it was in use before being interrupted by the analog timer
    if (adc->adc0->adcWasInUse) {
        // restore ADC config, and restart conversion
        adc->adc0->loadConfig(&adc->adc0->adc_config);
        // avoid a conversion started by this isr to repeat itself
        adc->adc0->adcWasInUse = (uint8_t) false;
    }
}

/******* LOOP *******/

uint32_t lastLoop = millis();
void loop() {
    uint32_t now = millis();
    if (now - lastLoop > 10) {
        maintainMTS();
        maintainDrive();
        lastLoop = now;
    }
    maintainLeds();
    maintainRotary();
    maintainButton();
    display.maintain();
}

int32_t previousValue;

void maintainRotary() {
    int32_t value;
    value = rotary.read();
    if (value != previousValue) {
        int16_t delta = (int16_t) (previousValue - value);
        display.directionInput(delta);
        previousValue = value;
    }
}

bool wasPressed = false;
void maintainButton() {

    // Update the Bounce instance :
    debouncer.update();

    // Get the updated value :
    bool pressed = !debouncer.read();
    if (wasPressed != pressed) {
        display.pressInput(1, pressed);
        wasPressed = pressed;
        if (pressed) {
            Leds[LED_GREEN].on();
        } else {
            Leds[LED_GREEN].off();
        }
    }
}

// Each Led needs a `tick` to flash behaviour maintenance
void maintainLeds() {
    for (int i = 0; i < ledCount; i++) {
        Leds[i].tick();
    }
}

// When a new packet has been found, push parts of it into the display
// TODO: feed values into drive statistics (avg/min/max/etc)
void maintainDrive() {
    while(Packet *p = drive.nextPacket()) {
        // Process the packet by sending it's values to display for processing
        display.setChannel(0, p->lambda);
        if (p->channelCount >= 2) {
            display.setChannel(1, p->channel[1]);
            display.setChannel(2, p->channel[2]);
            display.setChannel(3, p->channel[3]);
//            display.setChannel(4, p->channel[4]);
        }
    }
    display.setElapsed(drive.elapsedMillis());
}

void maintainMTS() {
//    Leds[LED_BOARD].on();
    // TODO: Move serial input to interrupt timer
    int incomingAvailable = MTSSERIAL.available();
    if (incomingAvailable > 0) {
        Leds[LED_BOARD].on();
        uint8_t incomingRead = (uint8_t) MTSSERIAL.readBytes((char *) mtsbuffer, (size_t) incomingAvailable);
        if (incomingRead > 0) {
            // hand over bytes to packet buffer
            drive.addBytes((char *) mtsbuffer, incomingRead);
        }
        Leds[LED_BOARD].off();
    }
}<|endoftext|>