<commit_before>//=============================================================================
// ■ kernel.cpp
//-----------------------------------------------------------------------------
//   这个文件是干什么的？www
//=============================================================================

//---------------------------------------------------------------------------
// ● Multiboot
//---------------------------------------------------------------------------
void initialize_multiboot(type_address address) {
	int a = Memory::read32_at(address);
}

//---------------------------------------------------------------------------
// ● 主程序
//---------------------------------------------------------------------------
void initialize_main() {
	Terminal::width = 80;
	Terminal::height = 25;
	Terminal::write_char((struct pos) {4, 4}, '%', (struct Terminal::char_color) {
		.fg = Terminal::AQUA,
		.bg = Terminal::NAVY,
	});
	Graphics::width = 320;
	Graphics::height = 200;
	Graphics::fill_rect(16, 16, Graphics::width - 16 * 2,
		Graphics::height - 16 * 2, Graphics::TEAL);
	Graphics::set_pixel((struct pos) {16, 16}, Graphics::LIME);
	return;
}

//---------------------------------------------------------------------------
// ● 内核主程序
//---------------------------------------------------------------------------
extern "C" void kernel_main(type_address multiboot_info_address) {
	initialize_multiboot(multiboot_info_address);
	initialize_main();
}
<commit_msg>添加Multiboot信息支持，第二部分<commit_after>//=============================================================================
// ■ kernel.cpp
//-----------------------------------------------------------------------------
//   这个文件是干什么的？www
//=============================================================================

//---------------------------------------------------------------------------
// ● 处理Multiboot启动信息结构，参照：
//   https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
//---------------------------------------------------------------------------
void initialize_multiboot(type_address address) {
	uint32_t flags = Memory::read32_at(address);
	uint32_t mem_lower, mem_upper;
	if (flags & 1 << 0) {
		mem_lower = Memory::read32_at(address + 4);
		mem_upper = Memory::read32_at(address + 8);
	}
}

//---------------------------------------------------------------------------
// ● 主程序
//---------------------------------------------------------------------------
void initialize_main() {
	Terminal::width = 80;
	Terminal::height = 25;
	Terminal::write_char((struct pos) {4, 4}, '%', (struct Terminal::char_color) {
		.fg = Terminal::AQUA,
		.bg = Terminal::NAVY,
	});
	Graphics::width = 320;
	Graphics::height = 200;
	Graphics::fill_rect(16, 16, Graphics::width - 16 * 2,
		Graphics::height - 16 * 2, Graphics::TEAL);
	Graphics::set_pixel((struct pos) {16, 16}, Graphics::LIME);
	return;
}

//---------------------------------------------------------------------------
// ● 内核主程序
//---------------------------------------------------------------------------
extern "C" void kernel_main(type_address multiboot_info_address) {
	initialize_multiboot(multiboot_info_address);
	initialize_main();
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * This file defines the memory allocation hooks used on platforms
 * where we don't have a supported memory alloctor for memory tracking
 */

#include "config.h"

#include "alloc_hooks_dummy.h"

#include <memcached/extension_loggers.h>

void DummyAllocHooks::initialize() {
    get_stderr_logger()->log(EXTENSION_LOG_NOTICE, NULL,
                             "This version of Couchbase is built without "
                             "allocator hooks for accurate memory tracking");
}

bool DummyAllocHooks::add_new_hook(void (* hook)(const void* ptr, size_t size)) {
    return false;
}

bool DummyAllocHooks::remove_new_hook(void (* hook)(const void* ptr, size_t size)) {
    return false;
}

bool DummyAllocHooks::add_delete_hook(void (* hook)(const void* ptr)) {
    return false;
}

bool DummyAllocHooks::remove_delete_hook(void (* hook)(const void* ptr)) {
    return false;
}

int DummyAllocHooks::get_extra_stats_size() {
    return 0;
}

void DummyAllocHooks::get_allocator_stats(allocator_stats* stats) {
}

size_t DummyAllocHooks::get_allocation_size(const void* ptr) {
    return 0;
}

void DummyAllocHooks::get_detailed_stats(char* buffer, int size) {
    // empty
}

void DummyAllocHooks::release_free_memory() {
    // empty
}

bool DummyAllocHooks::enable_thread_cache(bool enable) {
    return true;
}

bool DummyAllocHooks::get_allocator_property(const char* name, size_t* value) {
    return false;
}

bool DummyAllocHooks::set_allocator_property(const char* name, size_t value) {
    return false;
}
<commit_msg>Enable basic memory tracking when using system allocator<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * This file defines the memory allocation hooks used on platforms
 * where we don't have a supported memory alloctor for memory tracking
 */

#include "config.h"

#include "alloc_hooks_dummy.h"

#include <memcached/extension_loggers.h>

void DummyAllocHooks::initialize() {
    get_stderr_logger()->log(EXTENSION_LOG_NOTICE, NULL,
                             "This version of Couchbase is built without "
                             "allocator hooks for accurate memory tracking");
}

bool DummyAllocHooks::add_new_hook(void (* hook)(const void* ptr, size_t size)) {
    return cb_add_new_hook(hook);
}

bool DummyAllocHooks::remove_new_hook(void (* hook)(const void* ptr, size_t size)) {
    return cb_remove_new_hook(hook);
}

bool DummyAllocHooks::add_delete_hook(void (* hook)(const void* ptr)) {
    return cb_add_delete_hook(hook);
}

bool DummyAllocHooks::remove_delete_hook(void (* hook)(const void* ptr)) {
    return cb_remove_delete_hook(hook);
}

int DummyAllocHooks::get_extra_stats_size() {
    return 0;
}

void DummyAllocHooks::get_allocator_stats(allocator_stats* stats) {
}

size_t DummyAllocHooks::get_allocation_size(const void* ptr) {
    return 0;
}

void DummyAllocHooks::get_detailed_stats(char* buffer, int size) {
    // empty
}

void DummyAllocHooks::release_free_memory() {
    // empty
}

bool DummyAllocHooks::enable_thread_cache(bool enable) {
    return true;
}

bool DummyAllocHooks::get_allocator_property(const char* name, size_t* value) {
    return false;
}

bool DummyAllocHooks::set_allocator_property(const char* name, size_t value) {
    return false;
}
<|endoftext|>


<commit_before>/*
    kopetemessage.cpp  -  Base class for Kopete messages

    Copyright (c) 2002-2003 by Martijn Klingens       <klingens@kde.org>

    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include <stdlib.h>

#include <qdatetime.h>
#include <qfont.h>
#include <qstylesheet.h>
#include <qregexp.h>
#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kmdcodec.h>

#include "kopeteemoticons.h"
#include "kopetemessage.h"
#include "kopetemetacontact.h"
#include "kopeteprefs.h"
#include "kopetexsl.h"

struct KopeteMessagePrivate
{
	uint refCount;

	const KopeteContact *from;
	KopeteContactPtrList to;
	QDomDocument xmlDoc;

	KopeteMessage::MessageDirection direction;
	KopeteMessage::MessageFormat format;
	KopeteMessage::MessageType type;
	KopeteMessage::MessageImportance importance;
	QDateTime timeStamp;

	bool bgOverride;
};

KopeteMessage::KopeteMessage()
{
	d = new KopeteMessagePrivate;

	init( QDateTime::currentDateTime(), 0L, KopeteContactPtrList(), QString::null, QString::null, Internal, PlainText, Chat );
}

KopeteMessage::KopeteMessage( const KopeteContact *fromKC, const KopeteContactPtrList &toKC, const QString &body,
	MessageDirection direction, MessageFormat f, MessageType type )
{
	d = new KopeteMessagePrivate;

	init( QDateTime::currentDateTime(), fromKC, toKC, body, QString::null, direction, f, type );
}

KopeteMessage::KopeteMessage( const KopeteContact *fromKC, const KopeteContactPtrList &toKC, const QString &body,
	const QString &subject, MessageDirection direction, MessageFormat f, MessageType type )
{
	d = new KopeteMessagePrivate;

	init( QDateTime::currentDateTime(), fromKC, toKC, body, subject, direction, f, type );
}

KopeteMessage::KopeteMessage( const QDateTime &timeStamp, const KopeteContact *fromKC, const KopeteContactPtrList &toKC,
	const QString &body, MessageDirection direction, MessageFormat f, MessageType type )
{
	d = new KopeteMessagePrivate;

	init( timeStamp, fromKC, toKC, body, QString::null, direction, f, type );
}

KopeteMessage::KopeteMessage( const QDateTime &timeStamp, const KopeteContact *fromKC, const KopeteContactPtrList &toKC,
	const QString &body, const QString &subject, MessageDirection direction, MessageFormat f, MessageType type )
{
	d = new KopeteMessagePrivate;

	init( timeStamp, fromKC, toKC, body, subject, direction, f, type );
}

KopeteMessage::KopeteMessage( const KopeteMessage &other )
{
	d = other.d;
	d->refCount++;
}

KopeteMessage& KopeteMessage::operator=( const KopeteMessage &other )
{
	if( other.d == d )
		return *this;

	detach();
	delete d;

	d = other.d;
	d->refCount++;

	return *this;
}

KopeteMessage::~KopeteMessage()
{
	d->refCount--;
	if( !d->refCount )
		delete d;
}

void KopeteMessage::setBgOverride( bool enabled )
{
	detach();
	d->bgOverride = enabled;
}

void KopeteMessage::setFg( const QColor &color )
{
	if( color.isValid() )
	{
		detach();
		QDomElement bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
		bodyNode.setAttribute( QString::fromLatin1("color"), color.name() );
	}
}

void KopeteMessage::setBg( const QColor &color )
{
	if( !d->bgOverride && color.isValid() )
	{
		detach();
		QDomElement bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
		bodyNode.setAttribute( QString::fromLatin1("bgcolor"), color.name() );
	}
}

void KopeteMessage::setFont( const QFont &font )
{
	detach();
	QDomElement bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
	bodyNode.setAttribute( QString::fromLatin1("font"), font.family() );
	bodyNode.setAttribute( QString::fromLatin1("fontsize"), font.pointSize() );
}

void KopeteMessage::setBody( const QString &body, MessageFormat f )
{
	detach();
	QDomCDATASection bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).firstChild().toCDATASection();
	bodyNode.setData( body );
	d->format = f;
}

void KopeteMessage::setImportance(KopeteMessage::MessageImportance i)
{
	detach();
	d->importance = i;
	d->xmlDoc.documentElement().setAttribute( QString::fromLatin1("importance"), i );
}

void KopeteMessage::init( const QDateTime &timeStamp, const KopeteContact *from, const KopeteContactPtrList &to,
	const QString &body, const QString &subject, MessageDirection direction, MessageFormat f, MessageType type )
{
	static QMap<QString,QColor> colorMap;
	static int lastColor;
	const QColor nameColors[] = {
		Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta,
		Qt::darkRed, Qt::darkGreen, Qt::darkCyan, Qt::darkMagenta, Qt::darkYellow
	};

	d->refCount = 1;
	d->from = from;
	d->to   = to;
	d->importance = (to.count() <= 1) ? Normal : Low;
	d->timeStamp = timeStamp;

	QDomElement messageNode = d->xmlDoc.createElement( QString::fromLatin1("message") );
	messageNode.setAttribute( QString::fromLatin1("time"), KGlobal::locale()->formatTime(timeStamp.time(), true) );
	messageNode.setAttribute( QString::fromLatin1("timestamp"), timeStamp.toString() );
	messageNode.setAttribute( QString::fromLatin1("subject"), subject );
	messageNode.setAttribute( QString::fromLatin1("direction"), direction );
	messageNode.setAttribute( QString::fromLatin1("importance"), d->importance );
	if( from )
		messageNode.setAttribute( QString::fromLatin1("mainContactId"), direction == Inbound ? d->from->contactId() : d->to.first()->contactId() );

	d->xmlDoc.appendChild( messageNode );

	if( from )
	{
		QDomElement fromNode = d->xmlDoc.createElement( QString::fromLatin1("from") );
		QDomElement fromContactNode = d->xmlDoc.createElement( QString::fromLatin1("contact") );
		fromContactNode.setAttribute( QString::fromLatin1("contactId"), from->contactId() );
		fromContactNode.setAttribute( QString::fromLatin1("contactDisplayName"), from->displayName() );
		QString fromName = from->metaContact() ? from->metaContact()->displayName() : from->displayName();
		fromContactNode.setAttribute( QString::fromLatin1("metaContactDisplayName"), fromName );
		fromNode.appendChild( fromContactNode );

		if( !colorMap.contains( fromName ) )
		{
			QColor newColor;
			if( direction == Outbound )
				newColor = Qt::yellow;
			else
				newColor = nameColors[(lastColor++) % (sizeof(nameColors) / sizeof(nameColors[0]))];
			colorMap.insert( fromName, newColor );
		}
		fromContactNode.setAttribute( QString::fromLatin1("color"), colorMap[ fromName ].name() );
		messageNode.appendChild( fromNode );
	}

	QDomElement toNode = d->xmlDoc.createElement( QString::fromLatin1("to") );
	for( KopeteContact *c = d->to.first(); c; c = d->to.next() )
	{
		QDomElement cNode = d->xmlDoc.createElement( QString::fromLatin1("contact") );
		cNode.setAttribute( QString::fromLatin1("contactId"), c->contactId() );
		cNode.setAttribute( QString::fromLatin1("contactDisplayName"), c->displayName() );
		cNode.setAttribute( QString::fromLatin1("metaContactDisplayName"), c->metaContact() ? c->metaContact()->displayName() : c->displayName() );
		toNode.appendChild( cNode );
	}
	messageNode.appendChild( toNode );

	QDomElement bodyNode = d->xmlDoc.createElement( QString::fromLatin1("body") );
	QDomCDATASection bodyText = d->xmlDoc.createCDATASection( body );
	bodyNode.appendChild( bodyText );

	messageNode.appendChild( bodyNode );

	d->format = f;
	d->bgOverride = false;
	d->type = type;
}

QString KopeteMessage::plainBody() const
{
	QDomElement bodyText = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();

	if( d->format == PlainText )
		return bodyText.text();
	else
		return KopeteXSL::unescape( bodyText.text() ).replace( QRegExp( QString::fromLatin1( "<[^>]*>" ) ), QString::fromLatin1( "" ) );
}

QString KopeteMessage::escapedBody() const
{
	QDomElement bodyText = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
	QString escapedBody = bodyText.text();

	if( d->format == PlainText )
	{
		escapedBody = QStyleSheet::escape( escapedBody );

		//Replace carriage returns inside the text
		escapedBody.replace( QRegExp( QString::fromLatin1( "\n" ) ), QString::fromLatin1( "
" ) );

		//Replace a tab with 4 spaces
		escapedBody.replace( QRegExp( QString::fromLatin1( "\t" ) ), QString::fromLatin1( "    " ) );

		//Replace multiple spaces with
		escapedBody.replace( QRegExp( QString::fromLatin1( "\\s\\s" ) ), QString::fromLatin1( "  " ) );
	}

	return escapedBody;
}

QString KopeteMessage::parsedBody() const
{
	QDomElement bodyText = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
	QString parsedBody = bodyText.text();

	if( d->format == ParsedHTML )
		return parsedBody;
	else
		return KopeteEmoticons::parseEmoticons(parseLinks(escapedBody()));
}

QString KopeteMessage::parseLinks( const QString &message ) const
{
	QString result = message;

	//Replace Email Links
	result.replace( QRegExp( QString::fromLatin1("\\b([\\w-_\\.]+@([-_\\w\\.]+\\.\\w+)+)\\b") ), QString::fromLatin1("\\1") );

	//Replace http/https/ftp links
	result.replace( QRegExp( QString::fromLatin1("\\b((http://\\w|ftp://\\w|https://\\w|www\\.)[\\w\\.-_]+[\\w\\./#&;:=\\?~%-_,]*)\\b") ), QString::fromLatin1("\\1" ) );

	return result;
}

const QDomDocument KopeteMessage::asXML() const
{
	QDomDocument doc = d->xmlDoc.cloneNode().toDocument();
	QDomCDATASection bodyText = doc.elementsByTagName( QString::fromLatin1("body") ).item(0).firstChild().toCDATASection();
	bodyText.setData( parsedBody() );
	return doc;
}

QDateTime KopeteMessage::timestamp() const
{
	return d->timeStamp;
}

const KopeteContact *KopeteMessage::from() const
{
	return d->from;
}

KopeteContactPtrList KopeteMessage::to() const
{
	return d->to;
}

KopeteMessage::MessageType KopeteMessage::type() const
{
	return d->type;
}

QColor KopeteMessage::fg() const
{
	return QColor( d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement().attribute( QString::fromLatin1("color") ) );
}

QColor KopeteMessage::bg() const
{
	return QColor( d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement().attribute( QString::fromLatin1("bgcolor") ) );
}

QFont KopeteMessage::font() const
{
	QDomElement bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
	return QFont( bodyNode.attribute( QString::fromLatin1("font") ), bodyNode.attribute( QString::fromLatin1("font") ).toInt() );
}

QString KopeteMessage::subject() const
{
	return d->xmlDoc.documentElement().attribute( QString::fromLatin1("subject") );
}

KopeteMessage::MessageFormat KopeteMessage::format() const
{
	return d->format;
}

KopeteMessage::MessageDirection KopeteMessage::direction() const
{
	return d->direction;
}

KopeteMessage::MessageImportance KopeteMessage::importance() const
{
	return d->importance;
}

void KopeteMessage::detach()
{
	if( d->refCount == 1 )
		return;

	// Warning: this only works as long as the private object doesn't contain pointers to allocated objects.
	// The from contact for example is fine, but it's a shallow copy this way.
	KopeteMessagePrivate *newD = new KopeteMessagePrivate(*d);
	newD->refCount = 1;
	d->refCount--;

	d = newD;
}

// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>fix strange and hard to find bug<commit_after>/*
    kopetemessage.cpp  -  Base class for Kopete messages

    Copyright (c) 2002-2003 by Martijn Klingens       <klingens@kde.org>

    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include <stdlib.h>

#include <qdatetime.h>
#include <qfont.h>
#include <qstylesheet.h>
#include <qregexp.h>
#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kmdcodec.h>

#include "kopeteemoticons.h"
#include "kopetemessage.h"
#include "kopetemetacontact.h"
#include "kopeteprefs.h"
#include "kopetexsl.h"

struct KopeteMessagePrivate
{
	uint refCount;

	const KopeteContact *from;
	KopeteContactPtrList to;
	QDomDocument xmlDoc;

	KopeteMessage::MessageDirection direction;
	KopeteMessage::MessageFormat format;
	KopeteMessage::MessageType type;
	KopeteMessage::MessageImportance importance;
	QDateTime timeStamp;

	bool bgOverride;
};

KopeteMessage::KopeteMessage()
{
	d = new KopeteMessagePrivate;

	init( QDateTime::currentDateTime(), 0L, KopeteContactPtrList(), QString::null, QString::null, Internal, PlainText, Chat );
}

KopeteMessage::KopeteMessage( const KopeteContact *fromKC, const KopeteContactPtrList &toKC, const QString &body,
	MessageDirection direction, MessageFormat f, MessageType type )
{
	d = new KopeteMessagePrivate;

	init( QDateTime::currentDateTime(), fromKC, toKC, body, QString::null, direction, f, type );
}

KopeteMessage::KopeteMessage( const KopeteContact *fromKC, const KopeteContactPtrList &toKC, const QString &body,
	const QString &subject, MessageDirection direction, MessageFormat f, MessageType type )
{
	d = new KopeteMessagePrivate;

	init( QDateTime::currentDateTime(), fromKC, toKC, body, subject, direction, f, type );
}

KopeteMessage::KopeteMessage( const QDateTime &timeStamp, const KopeteContact *fromKC, const KopeteContactPtrList &toKC,
	const QString &body, MessageDirection direction, MessageFormat f, MessageType type )
{
	d = new KopeteMessagePrivate;

	init( timeStamp, fromKC, toKC, body, QString::null, direction, f, type );
}

KopeteMessage::KopeteMessage( const QDateTime &timeStamp, const KopeteContact *fromKC, const KopeteContactPtrList &toKC,
	const QString &body, const QString &subject, MessageDirection direction, MessageFormat f, MessageType type )
{
	d = new KopeteMessagePrivate;

	init( timeStamp, fromKC, toKC, body, subject, direction, f, type );
}

KopeteMessage::KopeteMessage( const KopeteMessage &other )
{
	d = other.d;
	d->refCount++;
}

KopeteMessage& KopeteMessage::operator=( const KopeteMessage &other )
{
	if( other.d == d )
		return *this;

	detach();
	delete d;

	d = other.d;
	d->refCount++;

	return *this;
}

KopeteMessage::~KopeteMessage()
{
	d->refCount--;
	if( !d->refCount )
		delete d;
}

void KopeteMessage::setBgOverride( bool enabled )
{
	detach();
	d->bgOverride = enabled;
}

void KopeteMessage::setFg( const QColor &color )
{
	if( color.isValid() )
	{
		detach();
		QDomElement bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
		bodyNode.setAttribute( QString::fromLatin1("color"), color.name() );
	}
}

void KopeteMessage::setBg( const QColor &color )
{
	if( !d->bgOverride && color.isValid() )
	{
		detach();
		QDomElement bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
		bodyNode.setAttribute( QString::fromLatin1("bgcolor"), color.name() );
	}
}

void KopeteMessage::setFont( const QFont &font )
{
	detach();
	QDomElement bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
	bodyNode.setAttribute( QString::fromLatin1("font"), font.family() );
	bodyNode.setAttribute( QString::fromLatin1("fontsize"), font.pointSize() );
}

void KopeteMessage::setBody( const QString &body, MessageFormat f )
{
	detach();
	QDomCDATASection bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).firstChild().toCDATASection();
	bodyNode.setData( body );
	d->format = f;
}

void KopeteMessage::setImportance(KopeteMessage::MessageImportance i)
{
	detach();
	d->importance = i;
	d->xmlDoc.documentElement().setAttribute( QString::fromLatin1("importance"), i );
}

void KopeteMessage::init( const QDateTime &timeStamp, const KopeteContact *from, const KopeteContactPtrList &to,
	const QString &body, const QString &subject, MessageDirection direction, MessageFormat f, MessageType type )
{
	static QMap<QString,QColor> colorMap;
	static int lastColor;
	const QColor nameColors[] = {
		Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta,
		Qt::darkRed, Qt::darkGreen, Qt::darkCyan, Qt::darkMagenta, Qt::darkYellow
	};

	d->refCount = 1;
	d->from = from;
	d->to   = to;
	d->importance = (to.count() <= 1) ? Normal : Low;
	d->timeStamp = timeStamp;
	d->direction = direction;

	QDomElement messageNode = d->xmlDoc.createElement( QString::fromLatin1("message") );
	messageNode.setAttribute( QString::fromLatin1("time"), KGlobal::locale()->formatTime(timeStamp.time(), true) );
	messageNode.setAttribute( QString::fromLatin1("timestamp"), timeStamp.toString() );
	messageNode.setAttribute( QString::fromLatin1("subject"), subject );
	messageNode.setAttribute( QString::fromLatin1("direction"), direction );
	messageNode.setAttribute( QString::fromLatin1("importance"), d->importance );
	if( from )
		messageNode.setAttribute( QString::fromLatin1("mainContactId"), direction == Inbound ? d->from->contactId() : d->to.first()->contactId() );

	d->xmlDoc.appendChild( messageNode );

	if( from )
	{
		QDomElement fromNode = d->xmlDoc.createElement( QString::fromLatin1("from") );
		QDomElement fromContactNode = d->xmlDoc.createElement( QString::fromLatin1("contact") );
		fromContactNode.setAttribute( QString::fromLatin1("contactId"), from->contactId() );
		fromContactNode.setAttribute( QString::fromLatin1("contactDisplayName"), from->displayName() );
		QString fromName = from->metaContact() ? from->metaContact()->displayName() : from->displayName();
		fromContactNode.setAttribute( QString::fromLatin1("metaContactDisplayName"), fromName );
		fromNode.appendChild( fromContactNode );

		if( !colorMap.contains( fromName ) )
		{
			QColor newColor;
			if( direction == Outbound )
				newColor = Qt::yellow;
			else
				newColor = nameColors[(lastColor++) % (sizeof(nameColors) / sizeof(nameColors[0]))];
			colorMap.insert( fromName, newColor );
		}
		fromContactNode.setAttribute( QString::fromLatin1("color"), colorMap[ fromName ].name() );
		messageNode.appendChild( fromNode );
	}

	QDomElement toNode = d->xmlDoc.createElement( QString::fromLatin1("to") );
	for( KopeteContact *c = d->to.first(); c; c = d->to.next() )
	{
		QDomElement cNode = d->xmlDoc.createElement( QString::fromLatin1("contact") );
		cNode.setAttribute( QString::fromLatin1("contactId"), c->contactId() );
		cNode.setAttribute( QString::fromLatin1("contactDisplayName"), c->displayName() );
		cNode.setAttribute( QString::fromLatin1("metaContactDisplayName"), c->metaContact() ? c->metaContact()->displayName() : c->displayName() );
		toNode.appendChild( cNode );
	}
	messageNode.appendChild( toNode );

	QDomElement bodyNode = d->xmlDoc.createElement( QString::fromLatin1("body") );
	QDomCDATASection bodyText = d->xmlDoc.createCDATASection( body );
	bodyNode.appendChild( bodyText );

	messageNode.appendChild( bodyNode );

	d->format = f;
	d->bgOverride = false;
	d->type = type;
}

QString KopeteMessage::plainBody() const
{
	QDomElement bodyText = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();

	if( d->format == PlainText )
		return bodyText.text();
	else
		return KopeteXSL::unescape( bodyText.text() ).replace( QRegExp( QString::fromLatin1( "<[^>]*>" ) ), QString::fromLatin1( "" ) );
}

QString KopeteMessage::escapedBody() const
{
	QDomElement bodyText = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
	QString escapedBody = bodyText.text();

	if( d->format == PlainText )
	{
		escapedBody = QStyleSheet::escape( escapedBody );

		//Replace carriage returns inside the text
		escapedBody.replace( QRegExp( QString::fromLatin1( "\n" ) ), QString::fromLatin1( "
" ) );

		//Replace a tab with 4 spaces
		escapedBody.replace( QRegExp( QString::fromLatin1( "\t" ) ), QString::fromLatin1( "    " ) );

		//Replace multiple spaces with
		escapedBody.replace( QRegExp( QString::fromLatin1( "\\s\\s" ) ), QString::fromLatin1( "  " ) );
	}

	return escapedBody;
}

QString KopeteMessage::parsedBody() const
{
	QDomElement bodyText = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
	QString parsedBody = bodyText.text();

	if( d->format == ParsedHTML )
		return parsedBody;
	else
		return KopeteEmoticons::parseEmoticons(parseLinks(escapedBody()));
}

QString KopeteMessage::parseLinks( const QString &message ) const
{
	QString result = message;

	//Replace Email Links
	result.replace( QRegExp( QString::fromLatin1("\\b([\\w-_\\.]+@([-_\\w\\.]+\\.\\w+)+)\\b") ), QString::fromLatin1("\\1") );

	//Replace http/https/ftp links
	result.replace( QRegExp( QString::fromLatin1("\\b((http://\\w|ftp://\\w|https://\\w|www\\.)[\\w\\.-_]+[\\w\\./#&;:=\\?~%-_,]*)\\b") ), QString::fromLatin1("\\1" ) );

	return result;
}

const QDomDocument KopeteMessage::asXML() const
{
	QDomDocument doc = d->xmlDoc.cloneNode().toDocument();
	QDomCDATASection bodyText = doc.elementsByTagName( QString::fromLatin1("body") ).item(0).firstChild().toCDATASection();
	bodyText.setData( parsedBody() );
	return doc;
}

QDateTime KopeteMessage::timestamp() const
{
	return d->timeStamp;
}

const KopeteContact *KopeteMessage::from() const
{
	return d->from;
}

KopeteContactPtrList KopeteMessage::to() const
{
	return d->to;
}

KopeteMessage::MessageType KopeteMessage::type() const
{
	return d->type;
}

QColor KopeteMessage::fg() const
{
	return QColor( d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement().attribute( QString::fromLatin1("color") ) );
}

QColor KopeteMessage::bg() const
{
	return QColor( d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement().attribute( QString::fromLatin1("bgcolor") ) );
}

QFont KopeteMessage::font() const
{
	QDomElement bodyNode = d->xmlDoc.elementsByTagName( QString::fromLatin1("body") ).item(0).toElement();
	return QFont( bodyNode.attribute( QString::fromLatin1("font") ), bodyNode.attribute( QString::fromLatin1("font") ).toInt() );
}

QString KopeteMessage::subject() const
{
	return d->xmlDoc.documentElement().attribute( QString::fromLatin1("subject") );
}

KopeteMessage::MessageFormat KopeteMessage::format() const
{
	return d->format;
}

KopeteMessage::MessageDirection KopeteMessage::direction() const
{
	return d->direction;
}

KopeteMessage::MessageImportance KopeteMessage::importance() const
{
	return d->importance;
}

void KopeteMessage::detach()
{
	if( d->refCount == 1 )
		return;

	// Warning: this only works as long as the private object doesn't contain pointers to allocated objects.
	// The from contact for example is fine, but it's a shallow copy this way.
	KopeteMessagePrivate *newD = new KopeteMessagePrivate(*d);
	newD->refCount = 1;
	d->refCount--;

	d = newD;
}

// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Package:   pan_tilt
//
// Library:   libpan_tilt
//
// File:      ptCalib.cxx
//
/*! \file
 *
 * $LastChangedDate$
 * $Rev$
 *
 * \brief PanTiltCalib - Pan-Tilt calibration class implementation.
 *
 * \author Robin Knight   (robin.knight@roadnarrows.com)
 * \author Daniel Packard (daniel@roadnarrows.com)
 *
 * \par Copyright:
 * (C) 2014  RoadNarrows
 * (http://www.RoadNarrows.com)
 * \n All Rights Reserved
 */
/*
 * @EulaBegin@
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that
 * (1) The above copyright notice and the following two paragraphs
 * appear in all copies of the source code and (2) redistributions
 * including binaries reproduces these notices in the supporting
 * documentation.   Substantial modifications to this software may be
 * copyrighted by their authors and need not follow the licensing terms
 * described here, provided that the new terms are clearly indicated in
 * all files where they apply.
 *
 * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
 * OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
 * EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
 * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * @EulaEnd@
 */
////////////////////////////////////////////////////////////////////////////////

#include "rnr/rnrconfig.h"
#include "rnr/log.h"

#include "Dynamixel/Dynamixel.h"
#include "Dynamixel/DynaServo.h"

#include "pan_tilt/pan_tilt.h"
#include "pan_tilt/ptJoint.h"
#include "pan_tilt/ptCalib.h"
#include "pan_tilt/ptRobot.h"

using namespace std;
using namespace pan_tilt;

// ---------------------------------------------------------------------------
// Private Interface
// ---------------------------------------------------------------------------

// debug switch
#undef  CALIB_DEBUG_ENABLE

#ifdef CALIB_DEBUG_ENABLE

#define CALIB_DBG(servoid, fmt, ...) \
  do \
  { \
    fprintf(stderr, "DBG: %s(): Servo: %d: " fmt, \
      LOGFUNCNAME, servoid, ##__VA_ARGS__); \
    fflush(stderr); \
  } while(0)

#else

#define CALIB_DBG(servoid, fmt, ...)

#endif // CALIB_DEBUG_ENABLE

/*!
 * \brief Convenience macro for trying to get a servo object from dynamixel
 * chain.
 *
 * Failure is considered a software bug since the chain has already be
 * verified.
 *
 * Only works locally.
 *
 * \param [in] nServoId   Servo id.
 * \param [out] pServo    Pointer to associated servo object.
 *
 * \return On failure, forces return from calling function with the appropriate
 * error code.
 */
#define PT_TRY_GET_SERVO(nServoId, pServo) \
  do \
  { \
    if( (pServo = m_robot.m_pDynaChain->GetServo(nServoId)) == NULL ) \
    { \
      LOGERROR("BUG: Servo %d: Cannot find in dynamixel chain.", nServoId); \
      return -PT_ECODE_INTERNAL; \
    } \
  } while(0)

/*!
 * \brief Calibration order by master servo id.
 */
static const char *CalibOrder[] = { "pan", "tilt" };

int PanTiltCalib::calibrate()
{
  PanTiltRobot::MapRobotJoints::iterator  pos;

  PanTiltRobotJoint  *pJoint;
  int                 nServoId;
  size_t            i;
  int               rc;

  for(i=0, rc=PT_OK; (i<arraysize(CalibOrder)) && (rc >= 0); ++i)
  {
    nServoId = m_robot.getMasterServoId(CalibOrder[i]);

    // no joint in this product version with associated master servo id
    if( (pos = m_robot.m_kin.find(nServoId)) == m_robot.m_kin.end() )
    {
      continue;
    }

    pJoint = &(pos->second);

    // already calibrated
    if( pJoint->m_eOpState == PanTiltOpStateCalibrated )
    {
      continue;
    }

    pJoint->m_eOpState  = PanTiltOpStateCalibrating;

    // physical limits
    rc = calibrateJointByTorqueLimits(*pJoint);

    pJoint->m_eOpState =  rc == PT_OK? PanTiltOpStateCalibrated:
                                       PanTiltOpStateUncalibrated;
  }

  return rc;
}

int PanTiltCalib::calibrateJointByTorqueLimits(PanTiltRobotJoint &joint)
{
  static int    TuneCalSpeed  = 75;     // calibration speed
  static int    TuneBackoff   = 2;      // backoff position (ticks)

  int         nServoId;         // servo id
  DynaServo  *pServo;           // joint's master servo
  bool        bIsReverse;       // odometer is [not] reversed
  int         nOdStartPos;      // user's starting position
  int         nOdGoalPos;       // working goal position
  int         nOldMinLimit;     // original odometer minimum limit
  int         nOldMaxLimit;     // original odometer maximum limit
  int         nNewMinLimit;     // new odometer minimum limit
  int         nNewMaxLimit;     // new odometer maximum limit
  int         nDeltaMin;        // delta odometer minimums
  int         nDeltaMax;        // delta odometer maximums
  int         nDeltaAvg;        // delta average

  nServoId      = joint.m_nMasterServoId;
  nOldMinLimit  = joint.m_nMinPhyLimitOd;
  nOldMaxLimit  = joint.m_nMaxPhyLimitOd;
  bIsReverse    = joint.m_nMasterServoDir == DYNA_DIR_CCW? false: true;

  // dynamixel servo object in dynamixel chain
  PT_TRY_GET_SERVO(nServoId, pServo);

  nOdStartPos = pServo->GetOdometer();

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  // Find minimum joint limit.
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  LOGDIAG3("Joint %s (servo=%d): "
           "Determining minimum joint limit by torque limit.",
      joint.m_strName.c_str(), nServoId);

  //
  // A continuous mode servo must have its joint minimum limit within 360
  // degreees of joint rotation from the current position. Go to this endpoint
  // until the torque limit is found.
  //
  if( joint.m_eJointType == PanTiltJointTypeContinuous )
  {
    nOdGoalPos = M_TAU * -joint.m_fTicksPerJointRad;
  }

  //
  // A servo mode servo has encoder endpoints that are known and finite. Go to
  // the appropriate endpoint until the torque limit is found.
  //
  else
  {
    if( (nOdGoalPos = pServo->CalcOdometerAtEncMin()) > 0 )
    {
      nOdGoalPos = pServo->CalcOdometerAtEncMax();
    }
  }

  //LOGDIAG3("MOVE TO MINIMUM LIMIT.");
  moveWait(pServo, nOdGoalPos, TuneCalSpeed);

  nNewMinLimit = pServo->GetOdometer();

  //
  // Off load servo by moving back to starting calibration position.
  //
  //LOGDIAG3("MOVE BACK TO START.");
  moveWait(pServo, nOdStartPos, TuneCalSpeed);

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  // Find maximum limit.
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  LOGDIAG3("Joint %s (servo=%d): "
           "Determining maximum joint limit by torque limit.",
      joint.m_strName.c_str(), nServoId);

  //
  // A continuous mode servo must have its joint minimum limit within 360
  // degreees of joint rotation from the current position. Go to this endpoint
  // until the torque limit is found.
  //
  if( joint.m_eJointType == PanTiltJointTypeContinuous )
  {
    nOdGoalPos = M_TAU * joint.m_fTicksPerJointRad;
  }

  //
  // A servo mode servo has encoder endpoints that are known and finite. Go to
  // the appropriate endpoint until the torque limit is found.
  //
  else
  {
    if( (nOdGoalPos = pServo->CalcOdometerAtEncMin()) < 0 )
    {
      nOdGoalPos = pServo->CalcOdometerAtEncMax();
    }
  }

  //LOGDIAG3("MOVE TO MAXIMUM LIMIT.");
  moveWait(pServo, nOdGoalPos, TuneCalSpeed);

  nNewMaxLimit = pServo->GetOdometer();

  //
  // Off load servo by moving back to starting calibration position
  //
  //LOGDIAG3("MOVE BACK TO START AGAIN.");
  moveWait(pServo, nOdStartPos, TuneCalSpeed);

  //
  // Calculate best new zero degree point.
  //
  nDeltaMin = nNewMinLimit - nOldMinLimit;
  nDeltaMax = nNewMaxLimit - nOldMaxLimit;
  nDeltaAvg = (nDeltaMin + nDeltaMax) / 2;

  //
  // Move to new zero point position.
  //
  //LOGDIAG3("MOVE TO NEW ZERO=%d.", nOdStartPos+nDeltaAvg);
  moveWait(pServo, nOdStartPos+nDeltaAvg, TuneCalSpeed);

  //
  // Reset odometer to new zero degree position.
  //
  m_robot.resetOdometerForServo(nServoId, bIsReverse);

  //
  // Adjust limits and positions to adjusted zero degree point.
  //
  joint.m_nMinPhyLimitOd    = nNewMinLimit - nDeltaAvg;
  joint.m_nMaxPhyLimitOd    = nNewMaxLimit - nDeltaAvg;

  joint.m_fMinPhyLimitRads  = (double)joint.m_nMinPhyLimitOd /
                                      joint.m_fTicksPerJointRad;
  joint.m_fMaxPhyLimitRads  = (double)joint.m_nMaxPhyLimitOd /
                                      joint.m_fTicksPerJointRad;

  joint.m_nMinSoftLimitOd   = joint.m_nMinPhyLimitOd + TuneBackoff;
  joint.m_nMaxSoftLimitOd   = joint.m_nMaxPhyLimitOd - TuneBackoff;

  joint.m_fMinSoftLimitRads = (double)joint.m_nMinSoftLimitOd /
                                      joint.m_fTicksPerJointRad;
  joint.m_fMaxSoftLimitRads = (double)joint.m_nMaxSoftLimitOd /
                                      joint.m_fTicksPerJointRad;

  //
  // Finally move to ideal calibration position.
  //
  if( joint.m_fCalibPosRads != 0.0 )
  {
    nOdGoalPos = (int)(joint.m_fCalibPosRads * joint.m_fTicksPerJointRad);
    //LOGDIAG3("MOVE TO CALIB ZERO PT=%d.", nOdGoalPos);
    moveWait(pServo, nOdGoalPos, TuneCalSpeed);
  }

  //
  // Calibrated.
  //
  LOGDIAG3("Joint %s (servo=%d): Calibrated:\n"
          "  Torque [min, max] limits: [%.2lfdeg (od=%d), %.2lfdeg (od=%d)].",
      joint.m_strName.c_str(), nServoId,
      radToDeg(joint.m_fMinPhyLimitRads), joint.m_nMinPhyLimitOd,
      radToDeg(joint.m_fMaxPhyLimitRads), joint.m_nMaxPhyLimitOd);

  return PT_OK;
}

int PanTiltCalib::moveWait(DynaServo *pServo, int nOdGoalPos, int nSpeed)
{
  static uint_t TuneWaituSec  = 300000;
  static int    TuneDeltaErr  = 5;

  int   nOdBefore;
  int   nOdAfter;
  bool  bMoving;

  nSpeed *= pServo->CalcSpeedDir(nOdGoalPos);

  // start move
  pServo->MoveAtSpeedTo(nSpeed, nOdGoalPos);

  CALIB_DBG(pServo->GetServoId(), "moveWait: move at speed=%d to %d\n",
                nSpeed, nOdGoalPos);

  // wait until move is completed
  do
  {
    nOdBefore = pServo->GetOdometer();
    usleep(TuneWaituSec);   // pthread cancelation point
    nOdAfter = pServo->GetOdometer();

    CALIB_DBG(pServo->GetServoId(), "moveWait: curspeed=%d, curpos=%d\n",
          pServo->GetCurSpeed(), nOdAfter);

    pServo->ReadIsMoving(&bMoving);
  }
  while( bMoving );
  //while( iabs(nOdBefore - nOdAfter) > TuneDeltaErr );

  return pServo->GetOdometer();
}
<commit_msg>adjusted soft limits<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Package:   pan_tilt
//
// Library:   libpan_tilt
//
// File:      ptCalib.cxx
//
/*! \file
 *
 * $LastChangedDate$
 * $Rev$
 *
 * \brief PanTiltCalib - Pan-Tilt calibration class implementation.
 *
 * \author Robin Knight   (robin.knight@roadnarrows.com)
 * \author Daniel Packard (daniel@roadnarrows.com)
 *
 * \par Copyright:
 * (C) 2014  RoadNarrows
 * (http://www.RoadNarrows.com)
 * \n All Rights Reserved
 */
/*
 * @EulaBegin@
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that
 * (1) The above copyright notice and the following two paragraphs
 * appear in all copies of the source code and (2) redistributions
 * including binaries reproduces these notices in the supporting
 * documentation.   Substantial modifications to this software may be
 * copyrighted by their authors and need not follow the licensing terms
 * described here, provided that the new terms are clearly indicated in
 * all files where they apply.
 *
 * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
 * OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
 * EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
 * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * @EulaEnd@
 */
////////////////////////////////////////////////////////////////////////////////

#include "rnr/rnrconfig.h"
#include "rnr/log.h"

#include "Dynamixel/Dynamixel.h"
#include "Dynamixel/DynaServo.h"

#include "pan_tilt/pan_tilt.h"
#include "pan_tilt/ptJoint.h"
#include "pan_tilt/ptCalib.h"
#include "pan_tilt/ptRobot.h"

using namespace std;
using namespace pan_tilt;

// ---------------------------------------------------------------------------
// Private Interface
// ---------------------------------------------------------------------------

// debug switch
#undef  CALIB_DEBUG_ENABLE

#ifdef CALIB_DEBUG_ENABLE

#define CALIB_DBG(servoid, fmt, ...) \
  do \
  { \
    fprintf(stderr, "DBG: %s(): Servo: %d: " fmt, \
      LOGFUNCNAME, servoid, ##__VA_ARGS__); \
    fflush(stderr); \
  } while(0)

#else

#define CALIB_DBG(servoid, fmt, ...)

#endif // CALIB_DEBUG_ENABLE

/*!
 * \brief Convenience macro for trying to get a servo object from dynamixel
 * chain.
 *
 * Failure is considered a software bug since the chain has already be
 * verified.
 *
 * Only works locally.
 *
 * \param [in] nServoId   Servo id.
 * \param [out] pServo    Pointer to associated servo object.
 *
 * \return On failure, forces return from calling function with the appropriate
 * error code.
 */
#define PT_TRY_GET_SERVO(nServoId, pServo) \
  do \
  { \
    if( (pServo = m_robot.m_pDynaChain->GetServo(nServoId)) == NULL ) \
    { \
      LOGERROR("BUG: Servo %d: Cannot find in dynamixel chain.", nServoId); \
      return -PT_ECODE_INTERNAL; \
    } \
  } while(0)

/*!
 * \brief Calibration order by master servo id.
 */
static const char *CalibOrder[] = { "pan", "tilt" };

int PanTiltCalib::calibrate()
{
  PanTiltRobot::MapRobotJoints::iterator  pos;

  PanTiltRobotJoint  *pJoint;
  int                 nServoId;
  size_t            i;
  int               rc;

  for(i=0, rc=PT_OK; (i<arraysize(CalibOrder)) && (rc >= 0); ++i)
  {
    nServoId = m_robot.getMasterServoId(CalibOrder[i]);

    // no joint in this product version with associated master servo id
    if( (pos = m_robot.m_kin.find(nServoId)) == m_robot.m_kin.end() )
    {
      continue;
    }

    pJoint = &(pos->second);

    // already calibrated
    if( pJoint->m_eOpState == PanTiltOpStateCalibrated )
    {
      continue;
    }

    pJoint->m_eOpState  = PanTiltOpStateCalibrating;

    // physical limits
    rc = calibrateJointByTorqueLimits(*pJoint);

    pJoint->m_eOpState =  rc == PT_OK? PanTiltOpStateCalibrated:
                                       PanTiltOpStateUncalibrated;
  }

  return rc;
}

int PanTiltCalib::calibrateJointByTorqueLimits(PanTiltRobotJoint &joint)
{
  static int    TuneCalSpeed  = 75;     // calibration speed
  static int    TuneBackoff   = 15;     // backoff position (ticks)

  int         nServoId;         // servo id
  DynaServo  *pServo;           // joint's master servo
  bool        bIsReverse;       // odometer is [not] reversed
  int         nOdStartPos;      // user's starting position
  int         nOdGoalPos;       // working goal position
  int         nOldMinLimit;     // original odometer minimum limit
  int         nOldMaxLimit;     // original odometer maximum limit
  int         nNewMinLimit;     // new odometer minimum limit
  int         nNewMaxLimit;     // new odometer maximum limit
  int         nDeltaMin;        // delta odometer minimums
  int         nDeltaMax;        // delta odometer maximums
  int         nDeltaAvg;        // delta average

  nServoId      = joint.m_nMasterServoId;
  nOldMinLimit  = joint.m_nMinPhyLimitOd;
  nOldMaxLimit  = joint.m_nMaxPhyLimitOd;
  bIsReverse    = joint.m_nMasterServoDir == DYNA_DIR_CCW? false: true;

  // dynamixel servo object in dynamixel chain
  PT_TRY_GET_SERVO(nServoId, pServo);

  nOdStartPos = pServo->GetOdometer();

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  // Find minimum joint limit.
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  LOGDIAG3("Joint %s (servo=%d): "
           "Determining minimum joint limit by torque limit.",
      joint.m_strName.c_str(), nServoId);

  //
  // A continuous mode servo must have its joint minimum limit within 360
  // degreees of joint rotation from the current position. Go to this endpoint
  // until the torque limit is found.
  //
  if( joint.m_eJointType == PanTiltJointTypeContinuous )
  {
    nOdGoalPos = M_TAU * -joint.m_fTicksPerJointRad;
  }

  //
  // A servo mode servo has encoder endpoints that are known and finite. Go to
  // the appropriate endpoint until the torque limit is found.
  //
  else
  {
    if( (nOdGoalPos = pServo->CalcOdometerAtEncMin()) > 0 )
    {
      nOdGoalPos = pServo->CalcOdometerAtEncMax();
    }
  }

  //LOGDIAG3("MOVE TO MINIMUM LIMIT.");
  moveWait(pServo, nOdGoalPos, TuneCalSpeed);

  nNewMinLimit = pServo->GetOdometer();

  //
  // Off load servo by moving back to starting calibration position.
  //
  //LOGDIAG3("MOVE BACK TO START.");
  moveWait(pServo, nOdStartPos, TuneCalSpeed);

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  // Find maximum limit.
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  LOGDIAG3("Joint %s (servo=%d): "
           "Determining maximum joint limit by torque limit.",
      joint.m_strName.c_str(), nServoId);

  //
  // A continuous mode servo must have its joint minimum limit within 360
  // degreees of joint rotation from the current position. Go to this endpoint
  // until the torque limit is found.
  //
  if( joint.m_eJointType == PanTiltJointTypeContinuous )
  {
    nOdGoalPos = M_TAU * joint.m_fTicksPerJointRad;
  }

  //
  // A servo mode servo has encoder endpoints that are known and finite. Go to
  // the appropriate endpoint until the torque limit is found.
  //
  else
  {
    if( (nOdGoalPos = pServo->CalcOdometerAtEncMin()) < 0 )
    {
      nOdGoalPos = pServo->CalcOdometerAtEncMax();
    }
  }

  //LOGDIAG3("MOVE TO MAXIMUM LIMIT.");
  moveWait(pServo, nOdGoalPos, TuneCalSpeed);

  nNewMaxLimit = pServo->GetOdometer();

  //
  // Off load servo by moving back to starting calibration position
  //
  //LOGDIAG3("MOVE BACK TO START AGAIN.");
  moveWait(pServo, nOdStartPos, TuneCalSpeed);

  //
  // Calculate best new zero degree point.
  //
  nDeltaMin = nNewMinLimit - nOldMinLimit;
  nDeltaMax = nNewMaxLimit - nOldMaxLimit;
  nDeltaAvg = (nDeltaMin + nDeltaMax) / 2;

  //
  // Move to new zero point position.
  //
  //LOGDIAG3("MOVE TO NEW ZERO=%d.", nOdStartPos+nDeltaAvg);
  moveWait(pServo, nOdStartPos+nDeltaAvg, TuneCalSpeed);

  //
  // Reset odometer to new zero degree position.
  //
  m_robot.resetOdometerForServo(nServoId, bIsReverse);

  //
  // Adjust limits and positions to adjusted zero degree point.
  //
  joint.m_nMinPhyLimitOd    = nNewMinLimit - nDeltaAvg;
  joint.m_nMaxPhyLimitOd    = nNewMaxLimit - nDeltaAvg;

  joint.m_fMinPhyLimitRads  = (double)joint.m_nMinPhyLimitOd /
                                      joint.m_fTicksPerJointRad;
  joint.m_fMaxPhyLimitRads  = (double)joint.m_nMaxPhyLimitOd /
                                      joint.m_fTicksPerJointRad;

  joint.m_nMinSoftLimitOd   = joint.m_nMinPhyLimitOd + TuneBackoff;
  joint.m_nMaxSoftLimitOd   = joint.m_nMaxPhyLimitOd - TuneBackoff;

  joint.m_fMinSoftLimitRads = (double)joint.m_nMinSoftLimitOd /
                                      joint.m_fTicksPerJointRad;
  joint.m_fMaxSoftLimitRads = (double)joint.m_nMaxSoftLimitOd /
                                      joint.m_fTicksPerJointRad;

  //
  // Finally move to ideal calibration position.
  //
  if( joint.m_fCalibPosRads != 0.0 )
  {
    nOdGoalPos = (int)(joint.m_fCalibPosRads * joint.m_fTicksPerJointRad);
    //LOGDIAG3("MOVE TO CALIB ZERO PT=%d.", nOdGoalPos);
    moveWait(pServo, nOdGoalPos, TuneCalSpeed);
  }

  //
  // Calibrated.
  //
  LOGDIAG3("Joint %s (servo=%d): Calibrated:\n"
          "  Torque [min, max] limits: [%.2lfdeg (od=%d), %.2lfdeg (od=%d)].",
      joint.m_strName.c_str(), nServoId,
      radToDeg(joint.m_fMinPhyLimitRads), joint.m_nMinPhyLimitOd,
      radToDeg(joint.m_fMaxPhyLimitRads), joint.m_nMaxPhyLimitOd);

  return PT_OK;
}

int PanTiltCalib::moveWait(DynaServo *pServo, int nOdGoalPos, int nSpeed)
{
  static uint_t TuneWaituSec  = 300000;
  static int    TuneDeltaErr  = 5;

  int   nOdBefore;
  int   nOdAfter;
  bool  bMoving;

  nSpeed *= pServo->CalcSpeedDir(nOdGoalPos);

  // start move
  pServo->MoveAtSpeedTo(nSpeed, nOdGoalPos);

  CALIB_DBG(pServo->GetServoId(), "moveWait: move at speed=%d to %d\n",
                nSpeed, nOdGoalPos);

  // wait until move is completed
  do
  {
    nOdBefore = pServo->GetOdometer();
    usleep(TuneWaituSec);   // pthread cancelation point
    nOdAfter = pServo->GetOdometer();

    CALIB_DBG(pServo->GetServoId(), "moveWait: curspeed=%d, curpos=%d\n",
          pServo->GetCurSpeed(), nOdAfter);

    pServo->ReadIsMoving(&bMoving);
  }
  while( bMoving );
  //while( iabs(nOdBefore - nOdAfter) > TuneDeltaErr );

  return pServo->GetOdometer();
}
<|endoftext|>


<commit_before>#include "readxBee.h"

void xBeeClass::begin(long baud){
#if defined(__AVR_ATmega32U4__) || defined(__MK20DX128__) || defined(__AVR_ATmega2560__)
    Serial1.begin(baud);  // Set up Serial for Leonardo and Mega
    _serial = &Serial1;
#else
    Serial.begin(baud);   // Set up Serial for all others (Uno, etc)
    _serial = &Serial;
#endif
}

//##############################################################################
//############################ Public Methods ##################################
//##############################################################################

void xBeeClass::begin(HardwareSerial &HWserial, long baud){

    HWserial.begin(baud); // Set up Serial for a specified Serial object
    _serial = &HWserial;
}

void xBeeClass::begin(Stream &serial){
    _serial = &serial;  // Set a reference to a specified Stream object (Hard or Soft Serial)
}

<<<<<<< HEAD
=======
void xBeeClass::printReturn(char *pk){
}

>>>>>>> 5f1ff8462683e36366cc0a9196ab30bacf6e85ad
void xBeeClass::readPacket(int *pk){//Populates a char array with a packet from the serial buffer.
  int counter = 0;
  int temp;
    do{
      if(Serial.available()){
        temp = Serial.read();        //Reads the first element in serial buffer
          if(temp == 0x7e){          //Looking for the start delimiter
            pk[counter] = temp;
            counter++;
            }
      }
      else {break;};
    }while(counter == 0);
    do{
      if(Serial.available()){        //Reads the rest of the package
        temp = Serial.read();
        pk[counter] = temp;
        counter++;
        }
      }while(counter < 24);
}

bool xBeeClass::checkPacket(char *pk){//Generates checksum and compares with the one in the package
  int sum = 0;

  for(int i = 3; i < 23; i++){       //Generate sum from index 3-to-22 (until, not incl. the checksum itself)
    sum += pk[i];
  }

  if((0xff - sum) == pk[23]){        //Check with the checksum of the package
    return true;                     //ok, good package
  }
  else{
    return false;                    //error
  }
}

void xBeeClass::decodePacket(char *pk, int i){//Convert chars from packet to int, store in arrays, call average func
  emg1arr[i] = (int)((pk[19] << 8) | pk[20]);
  emg2arr[i] = (int)((pk[21] << 8) | pk[22]);
  accZarr[i] = (int)((pk[13] << 8) | pk[14]);
  accYarr[i] = (int)((pk[15] << 8) | pk[16]);
  accXarr[i] = (int)((pk[17] << 8) | pk[18]);

  emg1 = xBee.averageArr(emg1arr);
  emg2 = xBee.averageArr(emg2arr);
  accZ = xBee.averageArr(accZarr);
  accY = xBee.averageArr(accYarr);
  accX = xBee.averageArr(accXarr);
}

float xBeeClass::averageArr(int *arr){
  int s = 0;
  for(int i = 0; i < 10; i++){
    s += arr[i];
  }
  float avg = s/10;
  return(avg);
}

//##############################################################################
//########################## Private Methods ###################################
//##############################################################################

xBeeClass xBee;
<commit_msg>Cleanup<commit_after>#include "readxBee.h"

void xBeeClass::begin(long baud){
#if defined(__AVR_ATmega32U4__) || defined(__MK20DX128__) || defined(__AVR_ATmega2560__)
    Serial1.begin(baud);  // Set up Serial for Leonardo and Mega
    _serial = &Serial1;
#else
    Serial.begin(baud);   // Set up Serial for all others (Uno, etc)
    _serial = &Serial;
#endif
}

//##############################################################################
//############################ Public Methods ##################################
//##############################################################################

void xBeeClass::begin(HardwareSerial &HWserial, long baud){

    HWserial.begin(baud); // Set up Serial for a specified Serial object
    _serial = &HWserial;
}

void xBeeClass::begin(Stream &serial){
    _serial = &serial;  // Set a reference to a specified Stream object (Hard or Soft Serial)
}

void xBeeClass::readPacket(int *pk){//Populates a char array with a packet from the serial buffer.
  int counter = 0;
  int temp;
    do{
      if(Serial.available()){
        temp = Serial.read();        //Reads the first element in serial buffer
          if(temp == 0x7e){          //Looking for the start delimiter
            pk[counter] = temp;
            counter++;
            }
      }
      else {break;};
    }while(counter == 0);
    do{
      if(Serial.available()){        //Reads the rest of the package
        temp = Serial.read();
        pk[counter] = temp;
        counter++;
        }
      }while(counter < 24);
}

bool xBeeClass::checkPacket(char *pk){//Generates checksum and compares with the one in the package
  int sum = 0;

  for(int i = 3; i < 23; i++){       //Generate sum from index 3-to-22 (until, not incl. the checksum itself)
    sum += pk[i];
  }

  if((0xff - sum) == pk[23]){        //Check with the checksum of the package
    return true;                     //ok, good package
  }
  else{
    return false;                    //error
  }
}

void xBeeClass::decodePacket(char *pk, int i){//Convert chars from packet to int, store in arrays, call average func
  emg1arr[i] = (int)((pk[19] << 8) | pk[20]);
  emg2arr[i] = (int)((pk[21] << 8) | pk[22]);
  accZarr[i] = (int)((pk[13] << 8) | pk[14]);
  accYarr[i] = (int)((pk[15] << 8) | pk[16]);
  accXarr[i] = (int)((pk[17] << 8) | pk[18]);

  emg1 = xBee.averageArr(emg1arr);
  emg2 = xBee.averageArr(emg2arr);
  accZ = xBee.averageArr(accZarr);
  accY = xBee.averageArr(accYarr);
  accX = xBee.averageArr(accXarr);
}

float xBeeClass::averageArr(int *arr){
  int s = 0;
  for(int i = 0; i < 10; i++){
    s += arr[i];
  }
  float avg = s/10;
  return(avg);
}

//##############################################################################
//########################## Private Methods ###################################
//##############################################################################

xBeeClass xBee;
<|endoftext|>


<commit_before>// proxy_util_w23.cpp : Main methods of the DLL.

#include "stdafx.h"
#include "proxy_util_w32.h"

/*****************************************************************************
 * Class:     com_btr_proxy_search_desktop_win_Win32ProxyUtils
 * Method:    winHttpDetectAutoProxyConfigUrl
 * Signature: (I)Ljava/lang/String;
 ****************************************************************************/

JNIEXPORT jstring JNICALL Java_com_btr_proxy_search_desktop_win_Win32ProxyUtils_winHttpDetectAutoProxyConfigUrl
(JNIEnv *env, jobject source, jint mode) {

	LPWSTR ppwszAutoConfigUrl = NULL;
	BOOL result = WinHttpDetectAutoProxyConfigUrl( mode, &ppwszAutoConfigUrl );
	if (ppwszAutoConfigUrl == NULL) {
		return NULL;
	}

	jstring retValue = env->NewString((jchar*)ppwszAutoConfigUrl,
									wcslen(ppwszAutoConfigUrl));

	GlobalFree( ppwszAutoConfigUrl );

	return retValue;
}

/*****************************************************************************
 * Class:     com_btr_proxy_search_desktop_win_Win32ProxyUtils
 * Method:    winHttpGetDefaultProxyConfiguration
 * Signature: ()Ljava/lang/String;
 ****************************************************************************/

JNIEXPORT jstring JNICALL Java_com_btr_proxy_search_desktop_win_Win32ProxyUtils_winHttpGetDefaultProxyConfiguration
(JNIEnv *env, jobject source) {

	WINHTTP_PROXY_INFO proxyInfo;

    // Retrieve the default proxy configuration.
    BOOL result = WinHttpGetDefaultProxyConfiguration( &proxyInfo );
	if (result == FALSE) {
		// TODO what to do in case of error.
		DWORD errorCode = GetLastError();
	}

	int proxyTypeLen = 0;
	int proxyLen = 0;
	int proxyBypassLen = 0;

	LPWSTR proxyType = NULL;
	if (proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
		proxyType = L"PROXY ";
		proxyTypeLen = wcslen(proxyType);
	} else
	if (proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY) {
		proxyType = L"DIRECT ";
		proxyTypeLen = wcslen(proxyType);
	}
    if (proxyInfo.lpszProxy != NULL) {
		proxyLen += wcslen(proxyInfo.lpszProxy);
	}
    if (proxyInfo.lpszProxyBypass != NULL) {
		proxyBypassLen += wcslen(proxyInfo.lpszProxyBypass);
	}

	jstring retVal = proxyInfo.lpszProxy == NULL? NULL
		: env->NewString((jchar*)proxyInfo.lpszProxy, wcslen(proxyInfo.lpszProxy));

	if (proxyInfo.lpszProxy != NULL) {
        GlobalFree( proxyInfo.lpszProxy );
    }
    if (proxyInfo.lpszProxyBypass != NULL) {
        GlobalFree( proxyInfo.lpszProxyBypass );
    }
	return retVal;

	//int retValueLen = proxyTypeLen+proxyLen+1+proxyBypassLen+1;
	//int insertPos = 0;
	//LPWSTR combined = new WCHAR[retValueLen];
	//combined[retValueLen] = 0;

	//wcsncat_s(combined, retValueLen, proxyType, proxyTypeLen);
	//insertPos += proxyTypeLen;
	//retValueLen -= proxyTypeLen;

	//wcsncat_s(combined, retValueLen, proxyInfo.lpszProxy, proxyLen);
	//insertPos += proxyLen;
	//retValueLen -= proxyLen;

	//wcsncat_s(combined, retValueLen, TEXT("|"), 1);
	//insertPos += proxyLen;
	//retValueLen -= proxyLen;

	//wcsncat_s(combined, retValueLen, proxyInfo.lpszProxyBypass, proxyBypassLen);
	//insertPos += proxyBypassLen;
	//retValueLen -= proxyBypassLen;

 //   if (proxyInfo.lpszProxy != NULL) {
 //       GlobalFree( proxyInfo.lpszProxy );
 //   }
 //   if (proxyInfo.lpszProxyBypass != NULL) {
 //       GlobalFree( proxyInfo.lpszProxyBypass );
 //   }

	//jstring retVal = env->NewString((jchar*)combined, wcslen(combined));

	//return retVal;
}

/*****************************************************************************
 * Class:     com_btr_proxy_search_desktop_win_Win32ProxyUtils
 * Method:    WinHttpGetIEProxyConfigForCurrentUser
 * Signature: ()Lcom/btr/proxy/search/desktop/win/Win32IESettings;
 ****************************************************************************/

JNIEXPORT jobject JNICALL Java_com_btr_proxy_search_desktop_win_Win32ProxyUtils_winHttpGetIEProxyConfigForCurrentUser
(JNIEnv *env, jobject source) {

	WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyInfo;

    // Retrieve the IE proxy configuration.
    BOOL result = WinHttpGetIEProxyConfigForCurrentUser( &ieProxyInfo );
	if (result == FALSE) {
		DWORD errorCode = GetLastError();
		return NULL;
	}

	jboolean autoDetect = ieProxyInfo.fAutoDetect;
	jstring autoConfigUrl = NULL;
	jstring proxy = NULL;
	jstring proxyBypass = NULL;

	if (ieProxyInfo.lpszAutoConfigUrl != NULL) {
		autoConfigUrl = env->NewString((jchar*)ieProxyInfo.lpszAutoConfigUrl, wcslen(ieProxyInfo.lpszAutoConfigUrl));
        GlobalFree( ieProxyInfo.lpszAutoConfigUrl );
    }
    if (ieProxyInfo.lpszProxy != NULL) {
		proxy = env->NewString((jchar*)ieProxyInfo.lpszProxy, wcslen(ieProxyInfo.lpszProxy));
		GlobalFree( ieProxyInfo.lpszProxy );
    }
    if (ieProxyInfo.lpszProxyBypass != NULL) {
		proxyBypass = env->NewString((jchar*)ieProxyInfo.lpszProxyBypass, wcslen(ieProxyInfo.lpszProxyBypass));
		GlobalFree( ieProxyInfo.lpszProxyBypass );
    }

	// Build result container object.
	jclass retValueClass = env->FindClass("com/btr/proxy/search/desktop/win/Win32IESettings");
	if ( retValueClass == NULL ) {
		return NULL;
	}

	jmethodID jmid = env->GetMethodID(retValueClass, "<init>", "(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
	if (jmid == NULL) {
		return NULL;
	}

	// Win32IESettings(boolean autoDetect, String autoConfigUrl, String proxy, String proxyBypass)
	jobject retValue = env->NewObject(retValueClass, jmid, autoDetect, autoConfigUrl, proxy, proxyBypass);

	return retValue;
}

/*****************************************************************************
 * Class:     com_btr_proxy_search_desktop_win_Win32ProxyUtils
 * Method:    readUserHomedir
 * Signature: ()Ljava/lang/String;
 ****************************************************************************/

JNIEXPORT jstring JNICALL Java_com_btr_proxy_search_desktop_win_Win32ProxyUtils_readUserHomedir
(JNIEnv *env, jobject source) {
	HKEY key;
	int result = RegOpenKeyEx(HKEY_CURRENT_USER,
#ifdef _WIN64
				"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
#else
				L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
#endif
				0, KEY_QUERY_VALUE, &key);
	if (0 != ERROR_SUCCESS) {
		LPWSTR errorMsg = L"ERROR: Key open failed";
		return env->NewString((jchar*)errorMsg, wcslen(errorMsg));
	}

	BYTE pvData[1000];
	DWORD dataSize = 1000;

#ifdef _WIN64
	result = RegQueryValueEx(key, "AppData", NULL, NULL, pvData, &dataSize);
#else
	result = RegQueryValueEx(key, L"AppData", NULL, NULL, pvData, &dataSize);
#endif
	RegCloseKey(key);
	if (result != ERROR_SUCCESS) {
		LPWSTR errorMsg = L"ERROR: Read value failed";
		return env->NewString((jchar*)errorMsg, wcslen(errorMsg));
	}

	jstring retValue = env->NewString((jchar*)pvData, (dataSize-1)/2);
	return retValue;
}

<commit_msg>Fix for a changed class name.<commit_after>// proxy_util_w23.cpp : Main methods of the DLL.

#include "stdafx.h"
#include "proxy_util_w32.h"

/*****************************************************************************
 * Class:     com_btr_proxy_search_desktop_win_Win32ProxyUtils
 * Method:    winHttpDetectAutoProxyConfigUrl
 * Signature: (I)Ljava/lang/String;
 ****************************************************************************/

JNIEXPORT jstring JNICALL Java_com_btr_proxy_search_desktop_win_Win32ProxyUtils_winHttpDetectAutoProxyConfigUrl
(JNIEnv *env, jobject source, jint mode) {

	LPWSTR ppwszAutoConfigUrl = NULL;
	BOOL result = WinHttpDetectAutoProxyConfigUrl( mode, &ppwszAutoConfigUrl );
	if (ppwszAutoConfigUrl == NULL) {
		return NULL;
	}

	jstring retValue = env->NewString((jchar*)ppwszAutoConfigUrl,
									wcslen(ppwszAutoConfigUrl));

	GlobalFree( ppwszAutoConfigUrl );

	return retValue;
}

/*****************************************************************************
 * Class:     com_btr_proxy_search_desktop_win_Win32ProxyUtils
 * Method:    winHttpGetDefaultProxyConfiguration
 * Signature: ()Ljava/lang/String;
 ****************************************************************************/

JNIEXPORT jstring JNICALL Java_com_btr_proxy_search_desktop_win_Win32ProxyUtils_winHttpGetDefaultProxyConfiguration
(JNIEnv *env, jobject source) {

	WINHTTP_PROXY_INFO proxyInfo;

    // Retrieve the default proxy configuration.
    BOOL result = WinHttpGetDefaultProxyConfiguration( &proxyInfo );
	if (result == FALSE) {
		// TODO what to do in case of error.
		DWORD errorCode = GetLastError();
	}

	int proxyTypeLen = 0;
	int proxyLen = 0;
	int proxyBypassLen = 0;

	LPWSTR proxyType = NULL;
	if (proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
		proxyType = L"PROXY ";
		proxyTypeLen = wcslen(proxyType);
	} else
	if (proxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY) {
		proxyType = L"DIRECT ";
		proxyTypeLen = wcslen(proxyType);
	}
    if (proxyInfo.lpszProxy != NULL) {
		proxyLen += wcslen(proxyInfo.lpszProxy);
	}
    if (proxyInfo.lpszProxyBypass != NULL) {
		proxyBypassLen += wcslen(proxyInfo.lpszProxyBypass);
	}

	jstring retVal = proxyInfo.lpszProxy == NULL? NULL
		: env->NewString((jchar*)proxyInfo.lpszProxy, wcslen(proxyInfo.lpszProxy));

	if (proxyInfo.lpszProxy != NULL) {
        GlobalFree( proxyInfo.lpszProxy );
    }
    if (proxyInfo.lpszProxyBypass != NULL) {
        GlobalFree( proxyInfo.lpszProxyBypass );
    }
	return retVal;

	//int retValueLen = proxyTypeLen+proxyLen+1+proxyBypassLen+1;
	//int insertPos = 0;
	//LPWSTR combined = new WCHAR[retValueLen];
	//combined[retValueLen] = 0;

	//wcsncat_s(combined, retValueLen, proxyType, proxyTypeLen);
	//insertPos += proxyTypeLen;
	//retValueLen -= proxyTypeLen;

	//wcsncat_s(combined, retValueLen, proxyInfo.lpszProxy, proxyLen);
	//insertPos += proxyLen;
	//retValueLen -= proxyLen;

	//wcsncat_s(combined, retValueLen, TEXT("|"), 1);
	//insertPos += proxyLen;
	//retValueLen -= proxyLen;

	//wcsncat_s(combined, retValueLen, proxyInfo.lpszProxyBypass, proxyBypassLen);
	//insertPos += proxyBypassLen;
	//retValueLen -= proxyBypassLen;

 //   if (proxyInfo.lpszProxy != NULL) {
 //       GlobalFree( proxyInfo.lpszProxy );
 //   }
 //   if (proxyInfo.lpszProxyBypass != NULL) {
 //       GlobalFree( proxyInfo.lpszProxyBypass );
 //   }

	//jstring retVal = env->NewString((jchar*)combined, wcslen(combined));

	//return retVal;
}

/*****************************************************************************
 * Class:     com_btr_proxy_search_desktop_win_Win32ProxyUtils
 * Method:    WinHttpGetIEProxyConfigForCurrentUser
 * Signature: ()Lcom/btr/proxy/search/desktop/win/WinIESettings;
 ****************************************************************************/

JNIEXPORT jobject JNICALL Java_com_btr_proxy_search_desktop_win_Win32ProxyUtils_winHttpGetIEProxyConfigForCurrentUser
(JNIEnv *env, jobject source) {

	WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyInfo;

    // Retrieve the IE proxy configuration.
    BOOL result = WinHttpGetIEProxyConfigForCurrentUser( &ieProxyInfo );
	if (result == FALSE) {
		DWORD errorCode = GetLastError();
		return NULL;
	}

	jboolean autoDetect = ieProxyInfo.fAutoDetect;
	jstring autoConfigUrl = NULL;
	jstring proxy = NULL;
	jstring proxyBypass = NULL;

	if (ieProxyInfo.lpszAutoConfigUrl != NULL) {
		autoConfigUrl = env->NewString((jchar*)ieProxyInfo.lpszAutoConfigUrl, wcslen(ieProxyInfo.lpszAutoConfigUrl));
        GlobalFree( ieProxyInfo.lpszAutoConfigUrl );
    }
    if (ieProxyInfo.lpszProxy != NULL) {
		proxy = env->NewString((jchar*)ieProxyInfo.lpszProxy, wcslen(ieProxyInfo.lpszProxy));
		GlobalFree( ieProxyInfo.lpszProxy );
    }
    if (ieProxyInfo.lpszProxyBypass != NULL) {
		proxyBypass = env->NewString((jchar*)ieProxyInfo.lpszProxyBypass, wcslen(ieProxyInfo.lpszProxyBypass));
		GlobalFree( ieProxyInfo.lpszProxyBypass );
    }

	// Build result container object.
	jclass retValueClass = env->FindClass("com/btr/proxy/search/desktop/win/WinIESettings");
	if ( retValueClass == NULL ) {
		return NULL;
	}

	jmethodID jmid = env->GetMethodID(retValueClass, "<init>", "(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
	if (jmid == NULL) {
		return NULL;
	}

	// WinIESettings(boolean autoDetect, String autoConfigUrl, String proxy, String proxyBypass)
	jobject retValue = env->NewObject(retValueClass, jmid, autoDetect, autoConfigUrl, proxy, proxyBypass);

	return retValue;
}

/*****************************************************************************
 * Class:     com_btr_proxy_search_desktop_win_Win32ProxyUtils
 * Method:    readUserHomedir
 * Signature: ()Ljava/lang/String;
 ****************************************************************************/

JNIEXPORT jstring JNICALL Java_com_btr_proxy_search_desktop_win_Win32ProxyUtils_readUserHomedir
(JNIEnv *env, jobject source) {
	HKEY key;
	int result = RegOpenKeyEx(HKEY_CURRENT_USER,
#ifdef _WIN64
				"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
#else
				L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
#endif
				0, KEY_QUERY_VALUE, &key);
	if (0 != ERROR_SUCCESS) {
		LPWSTR errorMsg = L"ERROR: Key open failed";
		return env->NewString((jchar*)errorMsg, wcslen(errorMsg));
	}

	BYTE pvData[1000];
	DWORD dataSize = 1000;

#ifdef _WIN64
	result = RegQueryValueEx(key, "AppData", NULL, NULL, pvData, &dataSize);
#else
	result = RegQueryValueEx(key, L"AppData", NULL, NULL, pvData, &dataSize);
#endif
	RegCloseKey(key);
	if (result != ERROR_SUCCESS) {
		LPWSTR errorMsg = L"ERROR: Read value failed";
		return env->NewString((jchar*)errorMsg, wcslen(errorMsg));
	}

	jstring retValue = env->NewString((jchar*)pvData, (dataSize-1)/2);
	return retValue;
}

<|endoftext|>


<commit_before>#include "miningpage.h"
#include "ui_miningpage.h"

MiningPage::MiningPage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MiningPage)
{
    ui->setupUi(this);

    setFixedSize(400, 420);

    minerActive = false;

    minerProcess = new QProcess(this);
    minerProcess->setProcessChannelMode(QProcess::MergedChannels);

    readTimer = new QTimer(this);

    acceptedShares = 0;
    rejectedShares = 0;

    roundAcceptedShares = 0;
    roundRejectedShares = 0;

    initThreads = 0;

    connect(readTimer, SIGNAL(timeout()), this, SLOT(readProcessOutput()));

    connect(ui->startButton, SIGNAL(pressed()), this, SLOT(startPressed()));
    connect(ui->typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int)));
    connect(ui->debugCheckBox, SIGNAL(toggled(bool)), this, SLOT(debugToggled(bool)));
    connect(minerProcess, SIGNAL(started()), this, SLOT(minerStarted()));
    connect(minerProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(minerError(QProcess::ProcessError)));
    connect(minerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(minerFinished()));
    connect(minerProcess, SIGNAL(readyRead()), this, SLOT(readProcessOutput()));
}

MiningPage::~MiningPage()
{
    minerProcess->kill();

    delete ui;
}

void MiningPage::setModel(ClientModel *model)
{
    this->model = model;

    loadSettings();

    bool pool = model->getMiningType() == ClientModel::PoolMining;
    ui->threadsBox->setValue(model->getMiningThreads());
    ui->typeBox->setCurrentIndex(pool ? 1 : 0);
//    if (model->getMiningStarted())
//        startPressed();
}

void MiningPage::startPressed()
{
    initThreads = ui->threadsBox->value();

    if (minerActive == false)
    {
        saveSettings();

        if (getMiningType() == ClientModel::SoloMining)
            minerStarted();
        else
            startPoolMining();
    }
    else
    {
        if (getMiningType() == ClientModel::SoloMining)
            minerFinished();
        else
            stopPoolMining();
    }
}

void MiningPage::startPoolMining()
{
    QStringList args;
    QString url = ui->serverLine->text();
    if (!url.contains("http://"))
        url.prepend("http://");
    QString urlLine = QString("%1:%2").arg(url, ui->portLine->text());
    QString userpassLine = QString("%1:%2").arg(ui->usernameLine->text(), ui->passwordLine->text());
    args << "--algo" << "scrypt";
    args << "--scantime" << ui->scantimeBox->text().toAscii();
    args << "--url" << urlLine.toAscii();
    args << "--userpass" << userpassLine.toAscii();
    args << "--threads" << ui->threadsBox->text().toAscii();
    args << "--retries" << "-1"; // Retry forever.
    args << "-P"; // This is need for this to work correctly on Windows. Extra protocol dump helps flush the buffer quicker.

    threadSpeed.clear();

    acceptedShares = 0;
    rejectedShares = 0;

    roundAcceptedShares = 0;
    roundRejectedShares = 0;

    // If minerd is in current path, then use that. Otherwise, assume minerd is in the path somewhere.
    QString program = QDir::current().filePath("minerd");
    if (!QFile::exists(program))
        program = "minerd";

    if (ui->debugCheckBox->isChecked())
        ui->list->addItem(args.join(" ").prepend(" ").prepend(program));

    ui->mineSpeedLabel->setText("Speed: N/A");
    ui->shareCount->setText("Accepted: 0 - Rejected: 0");
    minerProcess->start(program,args);
    minerProcess->waitForStarted(-1);

    readTimer->start(500);
}

void MiningPage::stopPoolMining()
{
    ui->mineSpeedLabel->setText("");
    minerProcess->kill();
    readTimer->stop();
}

void MiningPage::saveSettings()
{
    model->setMiningDebug(ui->debugCheckBox->isChecked());
    model->setMiningScanTime(ui->scantimeBox->value());
    model->setMiningServer(ui->serverLine->text());
    model->setMiningPort(ui->portLine->text());
    model->setMiningUsername(ui->usernameLine->text());
    model->setMiningPassword(ui->passwordLine->text());
}

void MiningPage::loadSettings()
{
    ui->debugCheckBox->setChecked(model->getMiningDebug());
    ui->scantimeBox->setValue(model->getMiningScanTime());
    ui->serverLine->setText(model->getMiningServer());
    ui->portLine->setText(model->getMiningPort());
    ui->usernameLine->setText(model->getMiningUsername());
    ui->passwordLine->setText(model->getMiningPassword());
}

void MiningPage::readProcessOutput()
{
    QByteArray output;

    minerProcess->reset();

    output = minerProcess->readAll();

    QString outputString(output);

    if (!outputString.isEmpty())
    {
        QStringList list = outputString.split("\n", QString::SkipEmptyParts);
        int i;
        for (i=0; i<list.size(); i++)
        {
            QString line = list.at(i);

            // Ignore protocol dump
            if (!line.startsWith("[") || line.contains("JSON protocol") || line.contains("HTTP hdr"))
                continue;

            if (ui->debugCheckBox->isChecked())
            {
                ui->list->addItem(line.trimmed());
                ui->list->scrollToBottom();
            }

            if (line.contains("(yay!!!)"))
                reportToList("Share accepted", SHARE_SUCCESS, getTime(line));
            else if (line.contains("(booooo)"))
                reportToList("Share rejected", SHARE_FAIL, getTime(line));
            else if (line.contains("LONGPOLL detected new block"))
                reportToList("LONGPOLL detected a new block", LONGPOLL, getTime(line));
            else if (line.contains("Supported options:"))
                reportToList("Miner didn't start properly. Try checking your settings.", ERROR, NULL);
            else if (line.contains("The requested URL returned error: 403"))
                reportToList("Couldn't connect. Please check your username and password.", ERROR, NULL);
            else if (line.contains("HTTP request failed"))
                reportToList("Couldn't connect. Please check pool server and port.", ERROR, NULL);
            else if (line.contains("JSON-RPC call failed"))
                reportToList("Couldn't communicate with server. Retrying in 30 seconds.", ERROR, NULL);
            else if (line.contains("thread ") && line.contains("khash/s"))
            {
                QString threadIDstr = line.at(line.indexOf("thread ")+7);
                int threadID = threadIDstr.toInt();

                int threadSpeedindx = line.indexOf(",");
                QString threadSpeedstr = line.mid(threadSpeedindx);
                threadSpeedstr.chop(8);
                threadSpeedstr.remove(", ");
                threadSpeedstr.remove(" ");
                threadSpeedstr.remove('\n');
                double speed=0;
                speed = threadSpeedstr.toDouble();

                threadSpeed[threadID] = speed;

                updateSpeed();
            }
        }
    }
}

void MiningPage::minerError(QProcess::ProcessError error)
{
    if (error == QProcess::FailedToStart)
    {
        reportToList("Miner failed to start. Make sure you have the minerd executable and libraries in the same directory as Litecoin-QT.", ERROR, NULL);
    }
}

void MiningPage::minerFinished()
{
    if (getMiningType() == ClientModel::SoloMining)
        reportToList("Solo mining stopped.", ERROR, NULL);
    else
        reportToList("Miner exited.", ERROR, NULL);
    ui->list->addItem("");
    minerActive = false;
    resetMiningButton();
    model->setMining(getMiningType(), false, initThreads, 0);
}

void MiningPage::minerStarted()
{
    if (!minerActive)
        if (getMiningType() == ClientModel::SoloMining)
            reportToList("Solo mining started.", ERROR, NULL);
        else
            reportToList("Miner started. It usually takes a minute until the program starts reporting information.", STARTED, NULL);
    minerActive = true;
    resetMiningButton();
    model->setMining(getMiningType(), true, initThreads, 0);
}

void MiningPage::updateSpeed()
{
    double totalSpeed=0;
    int totalThreads=0;

    QMapIterator<int, double> iter(threadSpeed);
    while(iter.hasNext())
    {
        iter.next();
        totalSpeed += iter.value();
        totalThreads++;
    }

    // If all threads haven't reported the hash speed yet, make an assumption
    if (totalThreads != initThreads)
    {
        totalSpeed = (totalSpeed/totalThreads)*initThreads;
    }

    QString speedString = QString("%1").arg(totalSpeed);
    QString threadsString = QString("%1").arg(initThreads);

    QString acceptedString = QString("%1").arg(acceptedShares);
    QString rejectedString = QString("%1").arg(rejectedShares);

    QString roundAcceptedString = QString("%1").arg(roundAcceptedShares);
    QString roundRejectedString = QString("%1").arg(roundRejectedShares);

    if (totalThreads == initThreads)
        ui->mineSpeedLabel->setText(QString("Speed: %1 khash/sec - %2 thread(s)").arg(speedString, threadsString));
    else
        ui->mineSpeedLabel->setText(QString("Speed: ~%1 khash/sec - %2 thread(s)").arg(speedString, threadsString));

    ui->shareCount->setText(QString("Accepted: %1 (%3) - Rejected: %2 (%4)").arg(acceptedString, rejectedString, roundAcceptedString, roundRejectedString));

    model->setMining(getMiningType(), true, initThreads, totalSpeed*1000);
}

void MiningPage::reportToList(QString msg, int type, QString time)
{
    QString message;
    if (time == NULL)
        message = QString("[%1] - %2").arg(QTime::currentTime().toString(), msg);
    else
        message = QString("[%1] - %2").arg(time, msg);

    switch(type)
    {
        case SHARE_SUCCESS:
            acceptedShares++;
            roundAcceptedShares++;
            updateSpeed();
            break;

        case SHARE_FAIL:
            rejectedShares++;
            roundRejectedShares++;
            updateSpeed();
            break;

        case LONGPOLL:
            roundAcceptedShares = 0;
            roundRejectedShares = 0;
            break;

        default:
            break;
    }

    ui->list->addItem(message);
    ui->list->scrollToBottom();
}

// Function for fetching the time
QString MiningPage::getTime(QString time)
{
    if (time.contains("["))
    {
        time.resize(21);
        time.remove("[");
        time.remove("]");
        time.remove(0,11);

        return time;
    }
    else
        return NULL;
}

void MiningPage::enableMiningControls(bool enable)
{
    ui->typeBox->setEnabled(enable);
    ui->threadsBox->setEnabled(enable);
    ui->scantimeBox->setEnabled(enable);
    ui->serverLine->setEnabled(enable);
    ui->portLine->setEnabled(enable);
    ui->usernameLine->setEnabled(enable);
    ui->passwordLine->setEnabled(enable);
}

void MiningPage::enablePoolMiningControls(bool enable)
{
    ui->scantimeBox->setEnabled(enable);
    ui->serverLine->setEnabled(enable);
    ui->portLine->setEnabled(enable);
    ui->usernameLine->setEnabled(enable);
    ui->passwordLine->setEnabled(enable);
}

ClientModel::MiningType MiningPage::getMiningType()
{
    if (ui->typeBox->currentIndex() == 0)  // Solo Mining
    {
        return ClientModel::SoloMining;
    }
    else if (ui->typeBox->currentIndex() == 1)  // Pool Minig
    {
        return ClientModel::PoolMining;
    }
    return ClientModel::SoloMining;
}

void MiningPage::typeChanged(int index)
{
    if (index == 0)  // Solo Mining
    {
        enablePoolMiningControls(false);
    }
    else if (index == 1)  // Pool Minig
    {
        enablePoolMiningControls(true);
    }
}

void MiningPage::debugToggled(bool checked)
{
    model->setMiningDebug(checked);
}

void MiningPage::resetMiningButton()
{
    ui->startButton->setText(minerActive ? "Stop Mining" : "Start Mining");
    enableMiningControls(!minerActive);
}
<commit_msg>Update two sentences on the mining page.<commit_after>#include "miningpage.h"
#include "ui_miningpage.h"

MiningPage::MiningPage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MiningPage)
{
    ui->setupUi(this);

    setFixedSize(400, 420);

    minerActive = false;

    minerProcess = new QProcess(this);
    minerProcess->setProcessChannelMode(QProcess::MergedChannels);

    readTimer = new QTimer(this);

    acceptedShares = 0;
    rejectedShares = 0;

    roundAcceptedShares = 0;
    roundRejectedShares = 0;

    initThreads = 0;

    connect(readTimer, SIGNAL(timeout()), this, SLOT(readProcessOutput()));

    connect(ui->startButton, SIGNAL(pressed()), this, SLOT(startPressed()));
    connect(ui->typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int)));
    connect(ui->debugCheckBox, SIGNAL(toggled(bool)), this, SLOT(debugToggled(bool)));
    connect(minerProcess, SIGNAL(started()), this, SLOT(minerStarted()));
    connect(minerProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(minerError(QProcess::ProcessError)));
    connect(minerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(minerFinished()));
    connect(minerProcess, SIGNAL(readyRead()), this, SLOT(readProcessOutput()));
}

MiningPage::~MiningPage()
{
    minerProcess->kill();

    delete ui;
}

void MiningPage::setModel(ClientModel *model)
{
    this->model = model;

    loadSettings();

    bool pool = model->getMiningType() == ClientModel::PoolMining;
    ui->threadsBox->setValue(model->getMiningThreads());
    ui->typeBox->setCurrentIndex(pool ? 1 : 0);
//    if (model->getMiningStarted())
//        startPressed();
}

void MiningPage::startPressed()
{
    initThreads = ui->threadsBox->value();

    if (minerActive == false)
    {
        saveSettings();

        if (getMiningType() == ClientModel::SoloMining)
            minerStarted();
        else
            startPoolMining();
    }
    else
    {
        if (getMiningType() == ClientModel::SoloMining)
            minerFinished();
        else
            stopPoolMining();
    }
}

void MiningPage::startPoolMining()
{
    QStringList args;
    QString url = ui->serverLine->text();
    if (!url.contains("http://"))
        url.prepend("http://");
    QString urlLine = QString("%1:%2").arg(url, ui->portLine->text());
    QString userpassLine = QString("%1:%2").arg(ui->usernameLine->text(), ui->passwordLine->text());
    args << "--algo" << "scrypt";
    args << "--scantime" << ui->scantimeBox->text().toAscii();
    args << "--url" << urlLine.toAscii();
    args << "--userpass" << userpassLine.toAscii();
    args << "--threads" << ui->threadsBox->text().toAscii();
    args << "--retries" << "-1"; // Retry forever.
    args << "-P"; // This is needed for this to work correctly on Windows. Extra protocol dump helps flush the buffer quicker.

    threadSpeed.clear();

    acceptedShares = 0;
    rejectedShares = 0;

    roundAcceptedShares = 0;
    roundRejectedShares = 0;

    // If minerd is in current path, then use that. Otherwise, assume minerd is in the path somewhere.
    QString program = QDir::current().filePath("minerd");
    if (!QFile::exists(program))
        program = "minerd";

    if (ui->debugCheckBox->isChecked())
        ui->list->addItem(args.join(" ").prepend(" ").prepend(program));

    ui->mineSpeedLabel->setText("Speed: N/A");
    ui->shareCount->setText("Accepted: 0 - Rejected: 0");
    minerProcess->start(program,args);
    minerProcess->waitForStarted(-1);

    readTimer->start(500);
}

void MiningPage::stopPoolMining()
{
    ui->mineSpeedLabel->setText("");
    minerProcess->kill();
    readTimer->stop();
}

void MiningPage::saveSettings()
{
    model->setMiningDebug(ui->debugCheckBox->isChecked());
    model->setMiningScanTime(ui->scantimeBox->value());
    model->setMiningServer(ui->serverLine->text());
    model->setMiningPort(ui->portLine->text());
    model->setMiningUsername(ui->usernameLine->text());
    model->setMiningPassword(ui->passwordLine->text());
}

void MiningPage::loadSettings()
{
    ui->debugCheckBox->setChecked(model->getMiningDebug());
    ui->scantimeBox->setValue(model->getMiningScanTime());
    ui->serverLine->setText(model->getMiningServer());
    ui->portLine->setText(model->getMiningPort());
    ui->usernameLine->setText(model->getMiningUsername());
    ui->passwordLine->setText(model->getMiningPassword());
}

void MiningPage::readProcessOutput()
{
    QByteArray output;

    minerProcess->reset();

    output = minerProcess->readAll();

    QString outputString(output);

    if (!outputString.isEmpty())
    {
        QStringList list = outputString.split("\n", QString::SkipEmptyParts);
        int i;
        for (i=0; i<list.size(); i++)
        {
            QString line = list.at(i);

            // Ignore protocol dump
            if (!line.startsWith("[") || line.contains("JSON protocol") || line.contains("HTTP hdr"))
                continue;

            if (ui->debugCheckBox->isChecked())
            {
                ui->list->addItem(line.trimmed());
                ui->list->scrollToBottom();
            }

            if (line.contains("(yay!!!)"))
                reportToList("Share accepted", SHARE_SUCCESS, getTime(line));
            else if (line.contains("(booooo)"))
                reportToList("Share rejected", SHARE_FAIL, getTime(line));
            else if (line.contains("LONGPOLL detected new block"))
                reportToList("LONGPOLL detected a new block", LONGPOLL, getTime(line));
            else if (line.contains("Supported options:"))
                reportToList("Miner didn't start properly. Try checking your settings.", ERROR, NULL);
            else if (line.contains("The requested URL returned error: 403"))
                reportToList("Couldn't connect. Please check your username and password.", ERROR, NULL);
            else if (line.contains("HTTP request failed"))
                reportToList("Couldn't connect. Please check pool server and port.", ERROR, NULL);
            else if (line.contains("JSON-RPC call failed"))
                reportToList("Couldn't communicate with server. Retrying in 30 seconds.", ERROR, NULL);
            else if (line.contains("thread ") && line.contains("khash/s"))
            {
                QString threadIDstr = line.at(line.indexOf("thread ")+7);
                int threadID = threadIDstr.toInt();

                int threadSpeedindx = line.indexOf(",");
                QString threadSpeedstr = line.mid(threadSpeedindx);
                threadSpeedstr.chop(8);
                threadSpeedstr.remove(", ");
                threadSpeedstr.remove(" ");
                threadSpeedstr.remove('\n');
                double speed=0;
                speed = threadSpeedstr.toDouble();

                threadSpeed[threadID] = speed;

                updateSpeed();
            }
        }
    }
}

void MiningPage::minerError(QProcess::ProcessError error)
{
    if (error == QProcess::FailedToStart)
    {
        reportToList("Miner failed to start. Make sure you have the minerd executable and libraries in the same directory as Litecoin-Qt.", ERROR, NULL);
    }
}

void MiningPage::minerFinished()
{
    if (getMiningType() == ClientModel::SoloMining)
        reportToList("Solo mining stopped.", ERROR, NULL);
    else
        reportToList("Miner exited.", ERROR, NULL);
    ui->list->addItem("");
    minerActive = false;
    resetMiningButton();
    model->setMining(getMiningType(), false, initThreads, 0);
}

void MiningPage::minerStarted()
{
    if (!minerActive)
        if (getMiningType() == ClientModel::SoloMining)
            reportToList("Solo mining started.", ERROR, NULL);
        else
            reportToList("Miner started. You might not see any output for a few minutes.", STARTED, NULL);
    minerActive = true;
    resetMiningButton();
    model->setMining(getMiningType(), true, initThreads, 0);
}

void MiningPage::updateSpeed()
{
    double totalSpeed=0;
    int totalThreads=0;

    QMapIterator<int, double> iter(threadSpeed);
    while(iter.hasNext())
    {
        iter.next();
        totalSpeed += iter.value();
        totalThreads++;
    }

    // If all threads haven't reported the hash speed yet, make an assumption
    if (totalThreads != initThreads)
    {
        totalSpeed = (totalSpeed/totalThreads)*initThreads;
    }

    QString speedString = QString("%1").arg(totalSpeed);
    QString threadsString = QString("%1").arg(initThreads);

    QString acceptedString = QString("%1").arg(acceptedShares);
    QString rejectedString = QString("%1").arg(rejectedShares);

    QString roundAcceptedString = QString("%1").arg(roundAcceptedShares);
    QString roundRejectedString = QString("%1").arg(roundRejectedShares);

    if (totalThreads == initThreads)
        ui->mineSpeedLabel->setText(QString("Speed: %1 khash/sec - %2 thread(s)").arg(speedString, threadsString));
    else
        ui->mineSpeedLabel->setText(QString("Speed: ~%1 khash/sec - %2 thread(s)").arg(speedString, threadsString));

    ui->shareCount->setText(QString("Accepted: %1 (%3) - Rejected: %2 (%4)").arg(acceptedString, rejectedString, roundAcceptedString, roundRejectedString));

    model->setMining(getMiningType(), true, initThreads, totalSpeed*1000);
}

void MiningPage::reportToList(QString msg, int type, QString time)
{
    QString message;
    if (time == NULL)
        message = QString("[%1] - %2").arg(QTime::currentTime().toString(), msg);
    else
        message = QString("[%1] - %2").arg(time, msg);

    switch(type)
    {
        case SHARE_SUCCESS:
            acceptedShares++;
            roundAcceptedShares++;
            updateSpeed();
            break;

        case SHARE_FAIL:
            rejectedShares++;
            roundRejectedShares++;
            updateSpeed();
            break;

        case LONGPOLL:
            roundAcceptedShares = 0;
            roundRejectedShares = 0;
            break;

        default:
            break;
    }

    ui->list->addItem(message);
    ui->list->scrollToBottom();
}

// Function for fetching the time
QString MiningPage::getTime(QString time)
{
    if (time.contains("["))
    {
        time.resize(21);
        time.remove("[");
        time.remove("]");
        time.remove(0,11);

        return time;
    }
    else
        return NULL;
}

void MiningPage::enableMiningControls(bool enable)
{
    ui->typeBox->setEnabled(enable);
    ui->threadsBox->setEnabled(enable);
    ui->scantimeBox->setEnabled(enable);
    ui->serverLine->setEnabled(enable);
    ui->portLine->setEnabled(enable);
    ui->usernameLine->setEnabled(enable);
    ui->passwordLine->setEnabled(enable);
}

void MiningPage::enablePoolMiningControls(bool enable)
{
    ui->scantimeBox->setEnabled(enable);
    ui->serverLine->setEnabled(enable);
    ui->portLine->setEnabled(enable);
    ui->usernameLine->setEnabled(enable);
    ui->passwordLine->setEnabled(enable);
}

ClientModel::MiningType MiningPage::getMiningType()
{
    if (ui->typeBox->currentIndex() == 0)  // Solo Mining
    {
        return ClientModel::SoloMining;
    }
    else if (ui->typeBox->currentIndex() == 1)  // Pool Mining
    {
        return ClientModel::PoolMining;
    }
    return ClientModel::SoloMining;
}

void MiningPage::typeChanged(int index)
{
    if (index == 0)  // Solo Mining
    {
        enablePoolMiningControls(false);
    }
    else if (index == 1)  // Pool Mining
    {
        enablePoolMiningControls(true);
    }
}

void MiningPage::debugToggled(bool checked)
{
    model->setMiningDebug(checked);
}

void MiningPage::resetMiningButton()
{
    ui->startButton->setText(minerActive ? "Stop Mining" : "Start Mining");
    enableMiningControls(!minerActive);
}
<|endoftext|>