<commit_before>/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Aurel Popirtac <mailto:ext-Aurel.Popirtac@nokia.com>
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "credentialsaccessmanager.h"

#include "signond-common.h"
#include "ui-key-authorizer.h"
#include "misc.h"

#include <QFile>
#include <QBuffer>

#define RETURN_IF_NOT_INITIALIZED(return_value)                  \
    do {                                                         \
        if (!m_isInitialized) {                                  \
            m_error = NotInitialized;                            \
            TRACE() << "CredentialsAccessManager not initialized."; \
            return return_value;                                \
        }                                                       \
    } while (0)

using namespace SignonDaemonNS;

/* ---------------------- CAMConfiguration ---------------------- */

CAMConfiguration::CAMConfiguration()
        : m_storagePath(QLatin1String(signonDefaultStoragePath)),
          m_dbName(QLatin1String(signonDefaultDbName)),
          m_useEncryption(signonDefaultUseEncryption),
          m_fileSystemType(QLatin1String(signonDefaultFileSystemType)),
          m_fileSystemSize(signonMinumumDbSize),
          m_encryptionPassphrase(QByteArray())
{}

void CAMConfiguration::serialize(QIODevice *device)
{
    if (device == NULL)
        return;

    if (!device->open(QIODevice::ReadWrite)) {
        return;
    }

    QString buffer;
    QTextStream stream(&buffer);
    stream << "\n\n====== Credentials Access Manager Configuration ======\n\n";
    stream << "File system mount name " << encryptedFSPath() << '\n';
    stream << "File system format: " << m_fileSystemType << '\n';
    stream << "File system size:" << m_fileSystemSize << "megabytes\n";

    const char *usingEncryption = m_useEncryption ? "true" : "false";
    stream << "Using encryption: " << usingEncryption << '\n';
    stream << "Credentials database name: " << m_dbName << '\n';
    stream << "======================================================\n\n";
    device->write(buffer.toUtf8());
    device->close();
}

QString CAMConfiguration::metadataDBPath() const
{
    return m_storagePath + QDir::separator() + m_dbName;
}

QString CAMConfiguration::encryptedFSPath() const
{
    return m_storagePath +
        QDir::separator() +
        QLatin1String(signonDefaultFileSystemName);
}

/* ---------------------- CredentialsAccessManager ---------------------- */

CredentialsAccessManager *CredentialsAccessManager::m_pInstance = NULL;

CredentialsAccessManager::CredentialsAccessManager(QObject *parent)
        : QObject(parent),
          m_isInitialized(false),
          m_systemOpened(false),
          m_error(NoError),
          keyManagers(),
          m_pCredentialsDB(NULL),
          m_pCryptoFileSystemManager(NULL),
          m_keyHandler(NULL),
          m_keyAuthorizer(NULL),
          m_CAMConfiguration(CAMConfiguration())
{
}

CredentialsAccessManager::~CredentialsAccessManager()
{
    closeCredentialsSystem();

    m_pInstance = NULL;
}

CredentialsAccessManager *CredentialsAccessManager::instance(QObject *parent)
{
    if (!m_pInstance)
        m_pInstance = new CredentialsAccessManager(parent);

    return m_pInstance;
}

void CredentialsAccessManager::finalize()
{
    if (m_systemOpened)
        closeCredentialsSystem();

    if (m_pCryptoFileSystemManager)
        delete m_pCryptoFileSystemManager;

    // Disconnect all key managers
    foreach (SignOn::AbstractKeyManager *keyManager, keyManagers)
        keyManager->disconnect();

    m_isInitialized = false;
    m_error = NoError;
}

bool CredentialsAccessManager::init(const CAMConfiguration &camConfiguration)
{
    if (m_isInitialized) {
        TRACE() << "CAM already initialized.";
        m_error = AlreadyInitialized;
        return false;
    }

    m_CAMConfiguration = camConfiguration;

    QBuffer config;
    m_CAMConfiguration.serialize(&config);
    TRACE() << "\n\nInitualizing CredentialsAccessManager with configuration: " << config.data();

    if (m_CAMConfiguration.m_useEncryption) {
        //Initialize CryptoManager
        m_pCryptoFileSystemManager = new CryptoManager(this);
        QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemMounted()),
                         this, SLOT(onEncryptedFSMounted()));
        QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemUnmounting()),
                         this, SLOT(onEncryptedFSUnmounting()));
        m_pCryptoFileSystemManager->setFileSystemPath(m_CAMConfiguration.encryptedFSPath());
        m_pCryptoFileSystemManager->setFileSystemSize(m_CAMConfiguration.m_fileSystemSize);
        m_pCryptoFileSystemManager->setFileSystemType(m_CAMConfiguration.m_fileSystemType);

        m_keyHandler = new KeyHandler(this);

        m_keyAuthorizer = new UiKeyAuthorizer(m_keyHandler, this);
        QObject::connect(m_keyAuthorizer,
                         SIGNAL(keyAuthorizationQueried(const SignOn::Key,int)),
                         this,
                         SLOT(onKeyAuthorizationQueried(const SignOn::Key,int)));

        /* These signal connections should be done after instantiating the
         * KeyAuthorizer, so that the KeyAuthorizer's slot will be called
         * first (or we could connect to them in queued mode)
         */
        QObject::connect(m_keyHandler, SIGNAL(ready()),
                         this, SIGNAL(credentialsSystemReady()));
        QObject::connect(m_keyHandler, SIGNAL(keyInserted(SignOn::Key)),
                         this, SLOT(onKeyInserted(SignOn::Key)));
        QObject::connect(m_keyHandler,
                         SIGNAL(lastAuthorizedKeyRemoved(SignOn::Key)),
                         this,
                         SLOT(onLastAuthorizedKeyRemoved(SignOn::Key)));
        QObject::connect(m_keyHandler, SIGNAL(keyRemoved(SignOn::Key)),
                         this, SLOT(onKeyRemoved(SignOn::Key)));
        m_keyHandler->initialize(m_pCryptoFileSystemManager, keyManagers);
    }

    m_isInitialized = true;
    m_error = NoError;

    TRACE() << "CredentialsAccessManager successfully initialized...";
    return true;
}

void CredentialsAccessManager::addKeyManager(
    SignOn::AbstractKeyManager *keyManager)
{
    keyManagers.append(keyManager);
}

bool CredentialsAccessManager::openSecretsDB()
{
    //todo remove this variable after LUKS implementation becomes stable.
    QString dbPath;

    if (m_CAMConfiguration.m_useEncryption) {
        dbPath = m_pCryptoFileSystemManager->fileSystemMountPath()
            + QDir::separator()
            + m_CAMConfiguration.m_dbName;

        if (!m_pCryptoFileSystemManager->fileSystemIsMounted()) {
            /* Do not attempt to mount the FS; we know that it will be mounted
             * automatically, as soon as some encryption keys are provided */
            m_error = CredentialsDbNotMounted;
            return false;
        }
    } else {
        dbPath = m_CAMConfiguration.metadataDBPath() + QLatin1String(".creds");
    }

    TRACE() << "Database name: [" << dbPath << "]";

    if (!m_pCredentialsDB->openSecretsDB(dbPath))
        return false;

    m_error = NoError;
    return true;
}

bool CredentialsAccessManager::isSecretsDBOpen()
{
    return m_pCredentialsDB->isSecretsDBOpen();
}

bool CredentialsAccessManager::closeSecretsDB()
{
    m_pCredentialsDB->closeSecretsDB();

    if (m_CAMConfiguration.m_useEncryption) {
        if (!m_pCryptoFileSystemManager->unmountFileSystem()) {
            m_error = CredentialsDbUnmountFailed;
            return false;
        }
    }

    return true;
}

bool CredentialsAccessManager::openMetaDataDB()
{
    QString dbPath = m_CAMConfiguration.metadataDBPath();

    QFileInfo fileInfo(dbPath);
    if (!fileInfo.exists()) {
        QDir storageDir(fileInfo.dir());
        if (!storageDir.mkpath(storageDir.path())) {
            BLAME() << "Could not create storage directory:" <<
                storageDir.path();
            m_error = CredentialsDbSetupFailed;
            return false;
        }
        if (!setFilePermissions(storageDir.path(), signonFilePermissions))
            TRACE() << "Failed to set file permissions for the storage directory.";

        if (!setUserOwnership(storageDir.path()))
            TRACE() << "Failed to set User ownership for the storage directory.";
    }

    m_pCredentialsDB = new CredentialsDB(dbPath);

    bool dbFileExists = QFile::exists(dbPath);
    if (!m_pCredentialsDB->init()) {
        m_error = CredentialsDbConnectionError;
        return false;
    }

    if (!dbFileExists) {
        if (!setFilePermissions(dbPath, signonFilePermissions))
            TRACE() << "Failed to set file permissions for meta data db file.";

        if (!setUserOwnership(dbPath))
            TRACE() << "Failed to set User ownership for meta data db file.";
    }

    return true;
}

void CredentialsAccessManager::closeMetaDataDB()
{
    if (m_pCredentialsDB) {
        delete m_pCredentialsDB;
        m_pCredentialsDB = NULL;
    }
}

bool CredentialsAccessManager::openCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (!openMetaDataDB()) {
        BLAME() << "Couldn't open metadata DB!";
        return false;
    }

    if (!openSecretsDB()) {
        BLAME() << "Failed to open secrets DB.";
        /* Even if the secrets DB couldn't be opened, signond is still usable:
         * that's why we return "true" anyways. */
    }

    m_systemOpened = true;
    return true;
}

bool CredentialsAccessManager::closeCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (!credentialsSystemOpened())
        return true;

    bool allClosed = true;
    if (isSecretsDBOpen() && !closeSecretsDB())
        allClosed = false;

    closeMetaDataDB();

    m_error = NoError;
    m_systemOpened = false;
    return allClosed;
}

bool CredentialsAccessManager::deleteCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (m_systemOpened && !closeCredentialsSystem()) {
        /* The close operation failed: we cannot proceed */
        return false;
    }

    m_error = NoError;

    if (m_CAMConfiguration.m_useEncryption) {
        if (!m_pCryptoFileSystemManager->deleteFileSystem())
            m_error = CredentialsDbDeletionFailed;
    } else {
        QFile dbFile(m_CAMConfiguration.m_dbName);
        if (dbFile.exists()) {
            if (!dbFile.remove())
                m_error = CredentialsDbDeletionFailed;
        }
    }

    return m_error == NoError;
}

CredentialsDB *CredentialsAccessManager::credentialsDB() const
{
    RETURN_IF_NOT_INITIALIZED(NULL);

    return m_pCredentialsDB;
}

bool CredentialsAccessManager::isCredentialsSystemReady() const
{
    return (m_keyHandler != 0) ? m_keyHandler->isReady() : true;
}

void CredentialsAccessManager::onKeyInserted(const SignOn::Key key)
{
    TRACE() << "Key inserted.";

    if (!m_keyHandler->keyIsAuthorized(key))
        m_keyAuthorizer->queryKeyAuthorization(
            key, AbstractKeyAuthorizer::KeyInserted);
}

void CredentialsAccessManager::onLastAuthorizedKeyRemoved(const SignOn::Key key)
{
    Q_UNUSED(key);
    TRACE() << "All keys disabled. Closing secure storage.";
    if (isSecretsDBOpen() || m_pCryptoFileSystemManager->fileSystemIsMounted())
        if (!closeSecretsDB())
            BLAME() << "Error occurred while closing secure storage.";
}

void CredentialsAccessManager::onKeyRemoved(const SignOn::Key key)
{
    TRACE() << "Key removed.";

    if (m_keyHandler->keyIsAuthorized(key)) {
        if (!m_keyHandler->revokeKeyAuthorization(key)) {
            BLAME() << "Revoking key authorization failed";
        }
    }
}

void CredentialsAccessManager::onKeyAuthorizationQueried(const SignOn::Key key,
                                                         int result)
{
    TRACE() << "result:" << result;

    if (result != AbstractKeyAuthorizer::Denied) {
        KeyHandler::AuthorizeFlags flags = KeyHandler::None;
        if (result == AbstractKeyAuthorizer::Exclusive) {
            TRACE() << "Reformatting secure storage.";
            flags |= KeyHandler::FormatStorage;
        }

        if (!m_keyHandler->authorizeKey(key, flags)) {
            BLAME() << "Authorization failed";
        }
    }

    replyToSecureStorageEventNotifiers();
}

bool CredentialsAccessManager::keysAvailable() const
{
    if (m_keyHandler == 0) return false;
    return !m_keyHandler->insertedKeys().isEmpty();
}

void CredentialsAccessManager::replyToSecureStorageEventNotifiers()
{
    TRACE();
    //Notify secure storage notifiers if any.
    int eventType = SIGNON_SECURE_STORAGE_NOT_AVAILABLE;
    if (m_pCredentialsDB->isSecretsDBOpen())
        eventType = SIGNON_SECURE_STORAGE_AVAILABLE;

    // Signal objects that posted secure storage not available events
    foreach (EventSender object, m_secureStorageEventNotifiers) {
        if (object.isNull())
            continue;

        SecureStorageEvent *secureStorageEvent =
            new SecureStorageEvent((QEvent::Type)eventType);

        QCoreApplication::postEvent(
            object.data(),
            secureStorageEvent,
            Qt::HighEventPriority);
    }

    m_secureStorageEventNotifiers.clear();
}

void CredentialsAccessManager::customEvent(QEvent *event)
{
    TRACE() << "Custom event received.";
    if (event->type() != SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
        QObject::customEvent(event);
        return;
    }

    SecureStorageEvent *localEvent =
        static_cast<SecureStorageEvent *>(event);

    /* All senders of this event will receive a reply when
     * the secure storage becomes available or an error occurs. */
    m_secureStorageEventNotifiers.append(localEvent->m_sender);

    TRACE() << "Processing secure storage not available event.";
    if ((localEvent == 0) || (m_pCredentialsDB == 0)) {
        replyToSecureStorageEventNotifiers();
        QObject::customEvent(event);
        return;
    }

    //Double check if the secrets DB is indeed unavailable
    if (m_pCredentialsDB->isSecretsDBOpen()) {
        replyToSecureStorageEventNotifiers();
        QObject::customEvent(event);
        return;
    }

    SignOn::Key key; /* we don't specity any key */
    m_keyAuthorizer->queryKeyAuthorization(key,
                                           AbstractKeyAuthorizer::StorageNeeded);

    QObject::customEvent(event);
}

void CredentialsAccessManager::onEncryptedFSMounted()
{
    TRACE();
    if (!isSecretsDBOpen()) {
        if (openSecretsDB()) {
            TRACE() << "Secrets DB opened.";
        } else {
            BLAME() << "Failed to open secrets DB.";
        }
    } else {
        BLAME() << "Secrets DB already opened?";
    }
}

void CredentialsAccessManager::onEncryptedFSUnmounting()
{
    TRACE();
    if (isSecretsDBOpen()) {
        m_pCredentialsDB->closeSecretsDB();
    }
}

<commit_msg>Fixed signond crash.<commit_after>/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Aurel Popirtac <mailto:ext-Aurel.Popirtac@nokia.com>
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "credentialsaccessmanager.h"

#include "signond-common.h"
#include "ui-key-authorizer.h"
#include "misc.h"

#include <QFile>
#include <QBuffer>

#define RETURN_IF_NOT_INITIALIZED(return_value)                  \
    do {                                                         \
        if (!m_isInitialized) {                                  \
            m_error = NotInitialized;                            \
            TRACE() << "CredentialsAccessManager not initialized."; \
            return return_value;                                \
        }                                                       \
    } while (0)

using namespace SignonDaemonNS;

/* ---------------------- CAMConfiguration ---------------------- */

CAMConfiguration::CAMConfiguration()
        : m_storagePath(QLatin1String(signonDefaultStoragePath)),
          m_dbName(QLatin1String(signonDefaultDbName)),
          m_useEncryption(signonDefaultUseEncryption),
          m_fileSystemType(QLatin1String(signonDefaultFileSystemType)),
          m_fileSystemSize(signonMinumumDbSize),
          m_encryptionPassphrase(QByteArray())
{}

void CAMConfiguration::serialize(QIODevice *device)
{
    if (device == NULL)
        return;

    if (!device->open(QIODevice::ReadWrite)) {
        return;
    }

    QString buffer;
    QTextStream stream(&buffer);
    stream << "\n\n====== Credentials Access Manager Configuration ======\n\n";
    stream << "File system mount name " << encryptedFSPath() << '\n';
    stream << "File system format: " << m_fileSystemType << '\n';
    stream << "File system size:" << m_fileSystemSize << "megabytes\n";

    const char *usingEncryption = m_useEncryption ? "true" : "false";
    stream << "Using encryption: " << usingEncryption << '\n';
    stream << "Credentials database name: " << m_dbName << '\n';
    stream << "======================================================\n\n";
    device->write(buffer.toUtf8());
    device->close();
}

QString CAMConfiguration::metadataDBPath() const
{
    return m_storagePath + QDir::separator() + m_dbName;
}

QString CAMConfiguration::encryptedFSPath() const
{
    return m_storagePath +
        QDir::separator() +
        QLatin1String(signonDefaultFileSystemName);
}

/* ---------------------- CredentialsAccessManager ---------------------- */

CredentialsAccessManager *CredentialsAccessManager::m_pInstance = NULL;

CredentialsAccessManager::CredentialsAccessManager(QObject *parent)
        : QObject(parent),
          m_isInitialized(false),
          m_systemOpened(false),
          m_error(NoError),
          keyManagers(),
          m_pCredentialsDB(NULL),
          m_pCryptoFileSystemManager(NULL),
          m_keyHandler(NULL),
          m_keyAuthorizer(NULL),
          m_CAMConfiguration(CAMConfiguration())
{
}

CredentialsAccessManager::~CredentialsAccessManager()
{
    closeCredentialsSystem();

    m_pInstance = NULL;
}

CredentialsAccessManager *CredentialsAccessManager::instance(QObject *parent)
{
    if (!m_pInstance)
        m_pInstance = new CredentialsAccessManager(parent);

    return m_pInstance;
}

void CredentialsAccessManager::finalize()
{
    if (m_systemOpened)
        closeCredentialsSystem();

    if (m_pCryptoFileSystemManager)
        delete m_pCryptoFileSystemManager;

    // Disconnect all key managers
    foreach (SignOn::AbstractKeyManager *keyManager, keyManagers)
        keyManager->disconnect();

    m_isInitialized = false;
    m_error = NoError;
}

bool CredentialsAccessManager::init(const CAMConfiguration &camConfiguration)
{
    if (m_isInitialized) {
        TRACE() << "CAM already initialized.";
        m_error = AlreadyInitialized;
        return false;
    }

    m_CAMConfiguration = camConfiguration;

    QBuffer config;
    m_CAMConfiguration.serialize(&config);
    TRACE() << "\n\nInitualizing CredentialsAccessManager with configuration: " << config.data();

    if (m_CAMConfiguration.m_useEncryption) {
        //Initialize CryptoManager
        m_pCryptoFileSystemManager = new CryptoManager(this);
        QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemMounted()),
                         this, SLOT(onEncryptedFSMounted()));
        QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemUnmounting()),
                         this, SLOT(onEncryptedFSUnmounting()));
        m_pCryptoFileSystemManager->setFileSystemPath(m_CAMConfiguration.encryptedFSPath());
        m_pCryptoFileSystemManager->setFileSystemSize(m_CAMConfiguration.m_fileSystemSize);
        m_pCryptoFileSystemManager->setFileSystemType(m_CAMConfiguration.m_fileSystemType);

        m_keyHandler = new KeyHandler(this);

        m_keyAuthorizer = new UiKeyAuthorizer(m_keyHandler, this);
        QObject::connect(m_keyAuthorizer,
                         SIGNAL(keyAuthorizationQueried(const SignOn::Key,int)),
                         this,
                         SLOT(onKeyAuthorizationQueried(const SignOn::Key,int)));

        /* These signal connections should be done after instantiating the
         * KeyAuthorizer, so that the KeyAuthorizer's slot will be called
         * first (or we could connect to them in queued mode)
         */
        QObject::connect(m_keyHandler, SIGNAL(ready()),
                         this, SIGNAL(credentialsSystemReady()));
        QObject::connect(m_keyHandler, SIGNAL(keyInserted(SignOn::Key)),
                         this, SLOT(onKeyInserted(SignOn::Key)));
        QObject::connect(m_keyHandler,
                         SIGNAL(lastAuthorizedKeyRemoved(SignOn::Key)),
                         this,
                         SLOT(onLastAuthorizedKeyRemoved(SignOn::Key)));
        QObject::connect(m_keyHandler, SIGNAL(keyRemoved(SignOn::Key)),
                         this, SLOT(onKeyRemoved(SignOn::Key)));
        m_keyHandler->initialize(m_pCryptoFileSystemManager, keyManagers);
    }

    m_isInitialized = true;
    m_error = NoError;

    TRACE() << "CredentialsAccessManager successfully initialized...";
    return true;
}

void CredentialsAccessManager::addKeyManager(
    SignOn::AbstractKeyManager *keyManager)
{
    keyManagers.append(keyManager);
}

bool CredentialsAccessManager::openSecretsDB()
{
    //todo remove this variable after LUKS implementation becomes stable.
    QString dbPath;

    if (m_CAMConfiguration.m_useEncryption) {
        dbPath = m_pCryptoFileSystemManager->fileSystemMountPath()
            + QDir::separator()
            + m_CAMConfiguration.m_dbName;

        if (!m_pCryptoFileSystemManager->fileSystemIsMounted()) {
            /* Do not attempt to mount the FS; we know that it will be mounted
             * automatically, as soon as some encryption keys are provided */
            m_error = CredentialsDbNotMounted;
            return false;
        }
    } else {
        dbPath = m_CAMConfiguration.metadataDBPath() + QLatin1String(".creds");
    }

    TRACE() << "Database name: [" << dbPath << "]";

    if (!m_pCredentialsDB->openSecretsDB(dbPath))
        return false;

    m_error = NoError;
    return true;
}

bool CredentialsAccessManager::isSecretsDBOpen()
{
    return m_pCredentialsDB->isSecretsDBOpen();
}

bool CredentialsAccessManager::closeSecretsDB()
{
    m_pCredentialsDB->closeSecretsDB();

    if (m_CAMConfiguration.m_useEncryption) {
        if (!m_pCryptoFileSystemManager->unmountFileSystem()) {
            m_error = CredentialsDbUnmountFailed;
            return false;
        }
    }

    return true;
}

bool CredentialsAccessManager::openMetaDataDB()
{
    QString dbPath = m_CAMConfiguration.metadataDBPath();

    QFileInfo fileInfo(dbPath);
    if (!fileInfo.exists()) {
        QDir storageDir(fileInfo.dir());
        if (!storageDir.mkpath(storageDir.path())) {
            BLAME() << "Could not create storage directory:" <<
                storageDir.path();
            m_error = CredentialsDbSetupFailed;
            return false;
        }
        if (!setFilePermissions(storageDir.path(), signonFilePermissions))
            TRACE() << "Failed to set file permissions for the storage directory.";

        if (!setUserOwnership(storageDir.path()))
            TRACE() << "Failed to set User ownership for the storage directory.";
    }

    m_pCredentialsDB = new CredentialsDB(dbPath);

    bool dbFileExists = QFile::exists(dbPath);
    if (!m_pCredentialsDB->init()) {
        m_error = CredentialsDbConnectionError;
        return false;
    }

    if (!dbFileExists) {
        if (!setFilePermissions(dbPath, signonFilePermissions))
            TRACE() << "Failed to set file permissions for meta data db file.";

        if (!setUserOwnership(dbPath))
            TRACE() << "Failed to set User ownership for meta data db file.";
    }

    return true;
}

void CredentialsAccessManager::closeMetaDataDB()
{
    if (m_pCredentialsDB) {
        delete m_pCredentialsDB;
        m_pCredentialsDB = NULL;
    }
}

bool CredentialsAccessManager::openCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (!openMetaDataDB()) {
        BLAME() << "Couldn't open metadata DB!";
        return false;
    }

    if (!openSecretsDB()) {
        BLAME() << "Failed to open secrets DB.";
        /* Even if the secrets DB couldn't be opened, signond is still usable:
         * that's why we return "true" anyways. */
    }

    m_systemOpened = true;
    return true;
}

bool CredentialsAccessManager::closeCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (!credentialsSystemOpened())
        return true;

    bool allClosed = true;
    if (isSecretsDBOpen() && !closeSecretsDB())
        allClosed = false;

    closeMetaDataDB();

    m_error = NoError;
    m_systemOpened = false;
    return allClosed;
}

bool CredentialsAccessManager::deleteCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (m_systemOpened && !closeCredentialsSystem()) {
        /* The close operation failed: we cannot proceed */
        return false;
    }

    m_error = NoError;

    if (m_CAMConfiguration.m_useEncryption) {
        if (!m_pCryptoFileSystemManager->deleteFileSystem())
            m_error = CredentialsDbDeletionFailed;
    } else {
        QFile dbFile(m_CAMConfiguration.m_dbName);
        if (dbFile.exists()) {
            if (!dbFile.remove())
                m_error = CredentialsDbDeletionFailed;
        }
    }

    return m_error == NoError;
}

CredentialsDB *CredentialsAccessManager::credentialsDB() const
{
    RETURN_IF_NOT_INITIALIZED(NULL);

    return m_pCredentialsDB;
}

bool CredentialsAccessManager::isCredentialsSystemReady() const
{
    return (m_keyHandler != 0) ? m_keyHandler->isReady() : true;
}

void CredentialsAccessManager::onKeyInserted(const SignOn::Key key)
{
    TRACE() << "Key inserted.";

    if (!m_keyHandler->keyIsAuthorized(key))
        m_keyAuthorizer->queryKeyAuthorization(
            key, AbstractKeyAuthorizer::KeyInserted);
}

void CredentialsAccessManager::onLastAuthorizedKeyRemoved(const SignOn::Key key)
{
    Q_UNUSED(key);
    TRACE() << "All keys disabled. Closing secure storage.";
    if (isSecretsDBOpen() || m_pCryptoFileSystemManager->fileSystemIsMounted())
        if (!closeSecretsDB())
            BLAME() << "Error occurred while closing secure storage.";
}

void CredentialsAccessManager::onKeyRemoved(const SignOn::Key key)
{
    TRACE() << "Key removed.";

    if (m_keyHandler->keyIsAuthorized(key)) {
        if (!m_keyHandler->revokeKeyAuthorization(key)) {
            BLAME() << "Revoking key authorization failed";
        }
    }
}

void CredentialsAccessManager::onKeyAuthorizationQueried(const SignOn::Key key,
                                                         int result)
{
    TRACE() << "result:" << result;

    if (result != AbstractKeyAuthorizer::Denied) {
        KeyHandler::AuthorizeFlags flags = KeyHandler::None;
        if (result == AbstractKeyAuthorizer::Exclusive) {
            TRACE() << "Reformatting secure storage.";
            flags |= KeyHandler::FormatStorage;
        }

        if (!m_keyHandler->authorizeKey(key, flags)) {
            BLAME() << "Authorization failed";
        }
    }

    replyToSecureStorageEventNotifiers();
}

bool CredentialsAccessManager::keysAvailable() const
{
    if (m_keyHandler == 0) return false;
    return !m_keyHandler->insertedKeys().isEmpty();
}

void CredentialsAccessManager::replyToSecureStorageEventNotifiers()
{
    TRACE();
    //Notify secure storage notifiers if any.
    int eventType = SIGNON_SECURE_STORAGE_NOT_AVAILABLE;
    if ((m_pCredentialsDB != 0) && m_pCredentialsDB->isSecretsDBOpen())
        eventType = SIGNON_SECURE_STORAGE_AVAILABLE;

    // Signal objects that posted secure storage not available events
    foreach (EventSender object, m_secureStorageEventNotifiers) {
        if (object.isNull())
            continue;

        SecureStorageEvent *secureStorageEvent =
            new SecureStorageEvent((QEvent::Type)eventType);

        QCoreApplication::postEvent(
            object.data(),
            secureStorageEvent,
            Qt::HighEventPriority);
    }

    m_secureStorageEventNotifiers.clear();
}

void CredentialsAccessManager::customEvent(QEvent *event)
{
    TRACE() << "Custom event received.";
    if (event->type() != SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
        QObject::customEvent(event);
        return;
    }

    SecureStorageEvent *localEvent =
        static_cast<SecureStorageEvent *>(event);

    /* All senders of this event will receive a reply when
     * the secure storage becomes available or an error occurs. */
    m_secureStorageEventNotifiers.append(localEvent->m_sender);

    TRACE() << "Processing secure storage not available event.";
    if ((localEvent == 0) || (m_pCredentialsDB == 0)) {
        replyToSecureStorageEventNotifiers();
        QObject::customEvent(event);
        return;
    }

    //Double check if the secrets DB is indeed unavailable
    if (m_pCredentialsDB->isSecretsDBOpen()) {
        replyToSecureStorageEventNotifiers();
        QObject::customEvent(event);
        return;
    }

    SignOn::Key key; /* we don't specity any key */
    m_keyAuthorizer->queryKeyAuthorization(key,
                                           AbstractKeyAuthorizer::StorageNeeded);

    QObject::customEvent(event);
}

void CredentialsAccessManager::onEncryptedFSMounted()
{
    TRACE();
    if (!credentialsSystemOpened()) return;

    if (!isSecretsDBOpen()) {
        if (openSecretsDB()) {
            TRACE() << "Secrets DB opened.";
        } else {
            BLAME() << "Failed to open secrets DB.";
        }
    } else {
        BLAME() << "Secrets DB already opened?";
    }
}

void CredentialsAccessManager::onEncryptedFSUnmounting()
{
    TRACE();
    if (!credentialsSystemOpened()) return;

    if (isSecretsDBOpen()) {
        m_pCredentialsDB->closeSecretsDB();
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Lech Kulina
 *
 * This file is part of the Realms Of Steel.
 * For conditions of distribution and use, see copyright details in the LICENSE file.
 */
#include <Core/RawBuffer.h>

ros::RawBuffer::RawBuffer()
    : data(ROS_NULL)
    , size(0)
    , position(0) {
}

ros::RawBuffer::RawBuffer(U32 size)
    : data(ROS_NULL)
    , size(0)
    , position(0) {
    allocate(size);
}

ros::RawBuffer::~RawBuffer() {
    free();
}

ros::RawBuffer::RawBuffer(const RawBuffer& src)
    : data(ROS_NULL)
    , size(0)
    , position(0) {
    assign(src);
}

ros::RawBuffer& ros::RawBuffer::operator=(const RawBuffer& src) {
    assign(src);
    return *this;
}

bool ros::RawBuffer::allocate(U32 size) {
    free();
    if (size == 0) {
        return false;
    }

    data = new (std::nothrow) U8[size];
    if (!data) {
        return false;
    }
    memset(data, 0, size);
    this->size = size;

    return true;
}

void ros::RawBuffer::free() {
    delete []data;
    data = ROS_NULL;
    size = 0;
    position = 0;
}

bool ros::RawBuffer::assign(const RawBuffer& src) {
    if (this == &src) {
        return true;
    }

    if (src.isNull() || !allocate(src.getSize())) {
        return false;
    }
    memcpy(data, src.at<U8>(), src.getSize());

    return true;
}

bool ros::RawBuffer::resize(U32 size) {
    if (!this->data) {
        return allocate(size);
    }

    if (size == 0) {
        return false;
    }

    U8* data = new (std::nothrow) U8[size];
    if (!data) {
        return false;
    }
    memset(data, 0, size);
    memcpy(data, this->data, std::min(size, this->size));

    free();
    this->data = data;
    this->size = size;

    return true;
}

void ros::RawBuffer::clear() {
    if (data) {
        memset(data, 0, size);
    }
}

bool ros::RawBuffer::seek(S64 offset, BufferOrigin origin) const {
    if (!data) {
        return false;
    }
    if (offset == 0 && origin == BufferOrigin_Current) {
        return true;
    }

    switch(origin) {
        case BufferOrigin_Begin:
            if (offset >= static_cast<S64>(size)) {
                return false;
            }
            position = offset;
            break;
        case BufferOrigin_Current:
            if (position + offset >= static_cast<S64>(size) || position + offset < 0) {
                return false;
            }
            position += offset;
            break;
        case BufferOrigin_End:
            if (offset >= 0 || static_cast<S64>(size) + offset < 0) {
                return false;
            }
            position = size + offset;
            break;
    }

    return true;
}

bool ros::RawBuffer::rewind() const {
    if (!data) {
        return false;
    }
    position = 0;
    return true;
}

bool ros::RawBuffer::hasEnded() const {
    return position >= static_cast<S64>(size);
}

bool ros::RawBuffer::read(void* dst, U32 size) const {
    if (!data || position + size > this->size) {
        return false;
    }
    if (size == 0) {
        return true;
    }

    memcpy(dst, data + position, size);
    position += size;

    return true;
}

bool ros::RawBuffer::write(const void* src, U32 size) {
    if (!data || position + size > this->size)
        return false;
    if (size == 0) {
        return true;
    }

    memcpy(data + position, src, size);
    position += size;

    return true;
}
<commit_msg>Fix range check in RawBuffer::seek<commit_after>/*
 * Copyright (c) 2016 Lech Kulina
 *
 * This file is part of the Realms Of Steel.
 * For conditions of distribution and use, see copyright details in the LICENSE file.
 */
#include <Core/RawBuffer.h>

ros::RawBuffer::RawBuffer()
    : data(ROS_NULL)
    , size(0)
    , position(0) {
}

ros::RawBuffer::RawBuffer(U32 size)
    : data(ROS_NULL)
    , size(0)
    , position(0) {
    allocate(size);
}

ros::RawBuffer::~RawBuffer() {
    free();
}

ros::RawBuffer::RawBuffer(const RawBuffer& src)
    : data(ROS_NULL)
    , size(0)
    , position(0) {
    assign(src);
}

ros::RawBuffer& ros::RawBuffer::operator=(const RawBuffer& src) {
    assign(src);
    return *this;
}

bool ros::RawBuffer::allocate(U32 size) {
    free();
    if (size == 0) {
        return false;
    }

    data = new (std::nothrow) U8[size];
    if (!data) {
        return false;
    }
    memset(data, 0, size);
    this->size = size;

    return true;
}

void ros::RawBuffer::free() {
    delete []data;
    data = ROS_NULL;
    size = 0;
    position = 0;
}

bool ros::RawBuffer::assign(const RawBuffer& src) {
    if (this == &src) {
        return true;
    }

    if (src.isNull() || !allocate(src.getSize())) {
        return false;
    }
    memcpy(data, src.at<U8>(), src.getSize());

    return true;
}

bool ros::RawBuffer::resize(U32 size) {
    if (!this->data) {
        return allocate(size);
    }

    if (size == 0) {
        return false;
    }

    U8* data = new (std::nothrow) U8[size];
    if (!data) {
        return false;
    }
    memset(data, 0, size);
    memcpy(data, this->data, std::min(size, this->size));

    free();
    this->data = data;
    this->size = size;

    return true;
}

void ros::RawBuffer::clear() {
    if (data) {
        memset(data, 0, size);
    }
}

bool ros::RawBuffer::seek(S64 offset, BufferOrigin origin) const {
    if (!data) {
        return false;
    }
    if (offset == 0 && origin == BufferOrigin_Current) {
        return true;
    }

    switch(origin) {
        case BufferOrigin_Begin:
            if (offset >= static_cast<S64>(size)) {
                return false;
            }
            position = offset;
            break;
        case BufferOrigin_Current:
            if (position + offset > static_cast<S64>(size) || position + offset < 0) {
                return false;
            }
            position += offset;
            break;
        case BufferOrigin_End:
            if (offset >= 0 || static_cast<S64>(size) + offset < 0) {
                return false;
            }
            position = size + offset;
            break;
    }

    return true;
}

bool ros::RawBuffer::rewind() const {
    if (!data) {
        return false;
    }
    position = 0;
    return true;
}

bool ros::RawBuffer::hasEnded() const {
    return position >= static_cast<S64>(size);
}

bool ros::RawBuffer::read(void* dst, U32 size) const {
    if (!data || position + size > this->size) {
        return false;
    }
    if (size == 0) {
        return true;
    }

    memcpy(dst, data + position, size);
    position += size;

    return true;
}

bool ros::RawBuffer::write(const void* src, U32 size) {
    if (!data || position + size > this->size)
        return false;
    if (size == 0) {
        return true;
    }

    memcpy(data + position, src, size);
    position += size;

    return true;
}
<|endoftext|>


<commit_before>#include "include/cli.h"

//Constructor
PropertiesReader::PropertiesReader(std::string file_path) {
  //Open the file
  std::string line;

  struct stat buffer;
  if (stat (file_path.c_str(), &buffer) == 0) {

    std::ifstream file (file_path);

    if (file.is_open()) {
      while (getline (file, line) ) {
        //Read a line from the property file

        //Figure out if we have a blank or comment line
        bool keep_going = true;
        if (line.length() > 0) {
          if (line[0] != '/' || line[1] != '/') {
            int eq_pos = line.find("=", 0);
            std::string var_name = line.substr(0, eq_pos);
            std::string var_value = line.substr(eq_pos+1, line.length() - eq_pos);
            opts.emplace(var_name, var_value);
          }
        }
      }
      file.close();
    }
  }
  else
  {
    logging->error("CONFIGURE: Configuration File not found");
    return false;
  }
return true;
}

  //Does a key exist?
bool PropertiesReader::opt_exist( std::string key )
{
  auto search = opts.find(key);
  if (search != opts.end())
  {
    return true;
  }
  else
  {
    return false;
  }
}
<commit_msg>Properties Reader Fixes<commit_after>#include "include/properties_reader.h"

//Constructor
PropertiesReader::PropertiesReader(std::string file_path) {
  //Open the file
  std::string line;

  struct stat buffer;
  if (stat (file_path.c_str(), &buffer) == 0) {

    std::ifstream file (file_path);

    if (file.is_open()) {
      while (getline (file, line) ) {
        //Read a line from the property file

        //Figure out if we have a blank or comment line
        bool keep_going = true;
        if (line.length() > 0) {
          if (line[0] != '/' || line[1] != '/') {
            int eq_pos = line.find("=", 0);
            std::string var_name = line.substr(0, eq_pos);
            std::string var_value = line.substr(eq_pos+1, line.length() - eq_pos);
            opts.emplace(var_name, var_value);
          }
        }
      }
      file.close();
    }
  }
  else
  {
    logging->error("CONFIGURE: Configuration File not found");
    return false;
  }
return true;
}

  //Does a key exist?
bool PropertiesReader::opt_exist( std::string key )
{
  auto search = opts.find(key);
  if (search != opts.end())
  {
    return true;
  }
  return false;
}
<|endoftext|>


<commit_before>#include "nbt/nbt.h"

#include <iostream>
#include <iomanip>

using namespace std;

struct inspect_context {
  int width;
};

void begin_compound(inspect_context* inspect, nbt::String name) {
  cout << setw(inspect->width) << ""
       << "BEGIN Compound(" << name << ")" << endl;
  inspect->width += 2;
}

void end_compound(inspect_context* inspect, nbt::String name) {
  inspect->width -= 2;
  cout << setw(inspect->width) << ""
       << "END Compound(" << name << ")" << endl;
}

void begin_list(inspect_context* inspect, nbt::String name, nbt::Byte type, nbt::Int length) {
  cout << setw(inspect->width) << ""
       << "BEGIN List(" << name << ", 0x" << hex << (int)type << ", " << length << ")" << endl;
  inspect->width += 2;
}

void end_list(inspect_context* inspect, nbt::String name) {
  inspect->width -= 2;
  cout << setw(inspect->width) << ""
       << "END List(" << name << ")" << endl;
}

void register_long(inspect_context* inspect, nbt::String name, nbt::Long value) {
  cout << setw(inspect->width) << ""
       << "Long(" << name << "): " << dec << value << endl;
}

void register_short(inspect_context* inspect, nbt::String name, nbt::Short value) {
  cout << setw(inspect->width) << ""
       << "Short(" << name << "): " << value << endl;
}

void register_string(inspect_context* inspect, nbt::String name, nbt::String value) {
  cout << setw(inspect->width) << ""
       << "String(" << name << "): " << value << endl;
}

void register_float(inspect_context* inspect, nbt::String name, nbt::Float value) {
  cout << setw(inspect->width) << ""
       << "Float(" << name << "): " << value << endl;
}

void register_double(inspect_context* inspect, nbt::String name, nbt::Double value) {
  cout << setw(inspect->width) << ""
       << "Double(" << name << "): " << value << endl;
}

void register_int(inspect_context* inspect, nbt::String name, nbt::Int value) {
  cout << setw(inspect->width) << ""
       << "Int(" << name << "): " << value << endl;
}

void register_byte(inspect_context* inspect, nbt::String name, nbt::Byte value) {
  cout << setw(inspect->width) << ""
       << "Byte(" << name << "): 0x" << hex << (int)value << endl;
}

void register_byte_array(inspect_context* inspect, nbt::String name, nbt::ByteArray* value) {
  cout << setw(inspect->width) << ""
       << "ByteArray(" << name << "): " << "(binary blob)" << endl;
}

int main(int argc, char* argv[]) {
  if (argc < 2) {
    return 1;
  }

  inspect_context ctx;
  ctx.width = 0;

  nbt::Parser<inspect_context> parser(&ctx);
  parser.begin_compound = begin_compound;
  parser.end_compound = end_compound;
  parser.begin_list = begin_list;
  parser.end_list = end_list;
  parser.register_long = register_long;
  parser.register_short = register_short;
  parser.register_string = register_string;
  parser.register_float = register_float;
  parser.register_double = register_double;
  parser.register_int = register_int;
  parser.register_byte = register_byte;
  parser.register_byte_array = register_byte_array;
  parser.parse_file(argv[1]);
}
<commit_msg>Added proper inspection of types and deletion of array values<commit_after>#include "nbt/nbt.h"

#include <iostream>
#include <iomanip>

using namespace std;

struct inspect_context {
  int width;
};

void begin_compound(inspect_context* inspect, nbt::String name) {
  cout << setw(inspect->width) << ""
       << "BEGIN Compound(" << name << ")" << endl;
  inspect->width += 2;
}

void end_compound(inspect_context* inspect, nbt::String name) {
  inspect->width -= 2;
  cout << setw(inspect->width) << ""
       << "END Compound(" << name << ")" << endl;
}

void begin_list(inspect_context* inspect, nbt::String name, nbt::Byte type, nbt::Int length) {
  cout << setw(inspect->width) << ""
       << "BEGIN List(" << name << ", " << nbt::tag_string_map[type] << ", " << length << ")" << endl;
  inspect->width += 2;
}

void end_list(inspect_context* inspect, nbt::String name) {
  inspect->width -= 2;
  cout << setw(inspect->width) << ""
       << "END List(" << name << ")" << endl;
}

void register_long(inspect_context* inspect, nbt::String name, nbt::Long value) {
  cout << setw(inspect->width) << ""
       << "Long(" << name << "): " << dec << value << endl;
}

void register_short(inspect_context* inspect, nbt::String name, nbt::Short value) {
  cout << setw(inspect->width) << ""
       << "Short(" << name << "): " << value << endl;
}

void register_string(inspect_context* inspect, nbt::String name, nbt::String value) {
  cout << setw(inspect->width) << ""
       << "String(" << name << "): " << value << endl;
}

void register_float(inspect_context* inspect, nbt::String name, nbt::Float value) {
  cout << setw(inspect->width) << ""
       << "Float(" << name << "): " << value << endl;
}

void register_double(inspect_context* inspect, nbt::String name, nbt::Double value) {
  cout << setw(inspect->width) << ""
       << "Double(" << name << "): " << value << endl;
}

void register_int(inspect_context* inspect, nbt::String name, nbt::Int value) {
  cout << setw(inspect->width) << ""
       << "Int(" << name << "): " << value << endl;
}

void register_byte(inspect_context* inspect, nbt::String name, nbt::Byte value) {
  cout << setw(inspect->width) << ""
       << "Byte(" << name << "): 0x" << hex << (int)value << endl;
}

void register_byte_array(inspect_context* inspect, nbt::String name, nbt::ByteArray* value) {
  cout << setw(inspect->width) << ""
       << "ByteArray(" << name << "): " << "(binary blob)" << endl;
  delete value;
}

int main(int argc, char* argv[]) {
  if (argc < 2) {
    return 1;
  }

  inspect_context ctx;
  ctx.width = 0;

  nbt::Parser<inspect_context> parser(&ctx);
  parser.begin_compound = begin_compound;
  parser.end_compound = end_compound;
  parser.begin_list = begin_list;
  parser.end_list = end_list;
  parser.register_long = register_long;
  parser.register_short = register_short;
  parser.register_string = register_string;
  parser.register_float = register_float;
  parser.register_double = register_double;
  parser.register_int = register_int;
  parser.register_byte = register_byte;
  parser.register_byte_array = register_byte_array;
  parser.parse_file(argv[1]);
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2012-2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file motor_ramp.cpp
 * Application to test motor ramp up.
 *
 * @author Andreas Antener <andreas@uaventure.com>
 */

#include <px4_config.h>
#include <px4_defines.h>
#include <px4_tasks.h>
#include <px4_posix.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>
#include <poll.h>

#include <arch/board/board.h>
#include <drivers/drv_hrt.h>
#include <drivers/drv_pwm_output.h>
#include <uORB/uORB.h>
#include <uORB/topics/actuator_outputs.h>
#include <uORB/topics/control_state.h>
#include <platforms/px4_defines.h>

#include "systemlib/systemlib.h"
#include "systemlib/err.h"

static bool thread_should_exit = false;		/**< motor_ramp exit flag */
static bool thread_running = false;		/**< motor_ramp status flag */
static int motor_ramp_task;				/**< Handle of motor_ramp task / thread */

enum RampState {
	RAMP_INIT,
	RAMP_MIN,
	RAMP_RAMP,
	RAMP_WAIT
};

/**
 * motor_ramp management function.
 */
extern "C" __EXPORT int motor_ramp_main(int argc, char *argv[]);

/**
 * Mainloop of motor_ramp.
 */
int motor_ramp_thread_main(int argc, char *argv[]);

/**
 * Print the correct usage.
 */
static void usage(const char *reason);

static void
usage(const char *reason)
{
	if (reason) {
		PX4_WARN("%s\n", reason);
	}

	PX4_WARN("usage: motor_ramp {start|stop|status} [-p <additional params>]\n\n");
}

/**
 * The motor_ramp app only briefly exists to start
 * the background job. The stack size assigned in the
 * Makefile does only apply to this management task.
 *
 * The actual stack size should be set in the call
 * to task_create().
 */
int motor_ramp_main(int argc, char *argv[])
{
	if (argc < 2) {
		usage("missing command");
		return 1;
	}

	if (!strcmp(argv[1], "start")) {

		if (thread_running) {
			PX4_WARN("motor_ramp already running\n");
			/* this is not an error */
			return 0;
		}

		thread_should_exit = false;
		motor_ramp_task = px4_task_spawn_cmd("motor_ramp",
						     SCHED_DEFAULT,
						     SCHED_PRIORITY_DEFAULT,
						     2000,
						     motor_ramp_thread_main,
						     (argv) ? (char *const *)&argv[2] : (char *const *)NULL);
		return 0;
	}

	if (!strcmp(argv[1], "stop")) {
		thread_should_exit = true;
		return 0;
	}

	if (!strcmp(argv[1], "status")) {
		if (thread_running) {
			PX4_WARN("\trunning\n");

		} else {
			PX4_WARN("\tnot started\n");
		}

		return 0;
	}

	usage("unrecognized command");
	return 1;
}

void set_min_pwm(unsigned pwm_value)
{
	int ret;
	unsigned servo_count;
	char *dev = PWM_OUTPUT0_DEVICE_PATH;
	int fd = px4_open(dev, 0);

	if (fd < 0) {PX4_WARN("can't open %s", dev);}

	ret = px4_ioctl(fd, PWM_SERVO_GET_COUNT, (unsigned long)&servo_count);
	struct pwm_output_values pwm_values;
	memset(&pwm_values, 0, sizeof(pwm_values));

	pwm_values.channel_count = servo_count;

	for (int i = 0; i < servo_count; i++) {
		pwm_values.values[i] = pwm_value;
	}

	ret = px4_ioctl(fd, PWM_SERVO_SET_MIN_PWM, (long unsigned int)&pwm_values);

	if (ret != OK) {PX4_WARN("failed setting min values");}

	px4_close(fd);
}

void publish(orb_advert_t actuator_outputs_pub, struct actuator_outputs_s &actuator_outputs, float output)
{
	//PX4_WARN("[motor_ramp] publish %f", (double)output);
	for (int i = 0; i < actuator_outputs_s::NUM_ACTUATOR_OUTPUTS; i++) {
		actuator_outputs.output[i] = output;
	}

	orb_publish(ORB_ID(actuator_outputs), actuator_outputs_pub, &actuator_outputs);
}

int motor_ramp_thread_main(int argc, char *argv[])
{
	PX4_WARN("[motor_ramp] starting");

	thread_running = true;

	struct actuator_outputs_s actuator_outputs = {};
	orb_advert_t actuator_outputs_pub = orb_advertise(ORB_ID(actuator_outputs), &actuator_outputs);
	int ctrl_state_sub = orb_subscribe(ORB_ID(control_state));

	/* wakeup source */
	px4_pollfd_struct_t fds[1];

	/* Setup of loop */
	fds[0].fd = ctrl_state_sub;
	fds[0].events = POLLIN;

	float dt = 0.01f; // prevent division with 0
	float timer = 0.0f;
	hrt_abstime start = 0;
	hrt_abstime last_run = 0;

	enum RampState ramp_state = RAMP_INIT;
	unsigned min_pwm = 1100;
	float ramp_time = 0.5f;
	float output = 0.0f;

	publish(actuator_outputs_pub, actuator_outputs, 0.0f);

	while (!thread_should_exit) {
		if (last_run > 0) {
			dt = hrt_elapsed_time(&last_run) * 1e-6;

		} else {
			start = hrt_absolute_time();
		}

		last_run = hrt_absolute_time();
		timer = hrt_elapsed_time(&start) * 1e-6;

		/* wait for up to 500ms for data */
		int pret = px4_poll(&fds[0], (sizeof(fds) / sizeof(fds[0])), 100);

		/* timed out - periodic check for _task_should_exit, etc. */
		if (pret == 0) {
			continue;
		}

		/* this is undesirable but not much we can do - might want to flag unhappy status */
		if (pret < 0) {
			PX4_WARN("[motor_ramp] poll error %d", pret);
			continue;
		}

		switch (ramp_state) {
		case RAMP_INIT: {
				if (min_pwm > 1350) {
					thread_should_exit = true;
					PX4_WARN("[motor_ramp] pwm min too high %d", min_pwm);
					break;
				}

				PX4_WARN("[motor_ramp] setting pwm min %d", min_pwm);
				set_min_pwm(min_pwm);
				ramp_state = RAMP_MIN;
				break;
			}

		case RAMP_MIN: {
				if (timer > 3.0f) {
					PX4_WARN("[motor_ramp] min set, starting ramp");
					start = hrt_absolute_time();
					ramp_state = RAMP_RAMP;
				}

				break;
			}

		case RAMP_RAMP: {
				output += dt / ramp_time;

				if (output > 1.0f) {
					output = 1.0f;
					start = hrt_absolute_time();
					ramp_state = RAMP_WAIT;
					PX4_WARN("[motor_ramp] ramp finished, waiting");
				}

				publish(actuator_outputs_pub, actuator_outputs, output);
				break;
			}

		case RAMP_WAIT: {
				if (timer > 3.0f) {
					thread_should_exit = true;
					break;
				}

				break;
			}
		}
	}

	publish(actuator_outputs_pub, actuator_outputs, 0.0f);

	PX4_WARN("[motor_ramp] exiting");

	thread_running = false;

	return 0;
}
<commit_msg>added parameters to motor_ramp<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2012-2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file motor_ramp.cpp
 * Application to test motor ramp up.
 *
 * @author Andreas Antener <andreas@uaventure.com>
 */

#include <px4_config.h>
#include <px4_defines.h>
#include <px4_tasks.h>
#include <px4_posix.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>
#include <poll.h>

#include <arch/board/board.h>
#include <drivers/drv_hrt.h>
#include <drivers/drv_pwm_output.h>
#include <uORB/uORB.h>
#include <uORB/topics/actuator_outputs.h>
#include <uORB/topics/control_state.h>
#include <platforms/px4_defines.h>

#include "systemlib/systemlib.h"
#include "systemlib/err.h"

static bool _thread_should_exit = false;		/**< motor_ramp exit flag */
static bool _thread_running = false;		/**< motor_ramp status flag */
static int _motor_ramp_task;				/**< Handle of motor_ramp task / thread */
static float _ramp_time;
static int _min_pwm;
static orb_advert_t _actuator_outputs_pub = nullptr;

enum RampState {
	RAMP_INIT,
	RAMP_MIN,
	RAMP_RAMP,
	RAMP_WAIT
};

/**
 * motor_ramp management function.
 */
extern "C" __EXPORT int motor_ramp_main(int argc, char *argv[]);

/**
 * Mainloop of motor_ramp.
 */
int motor_ramp_thread_main(int argc, char *argv[]);

bool min_pwm_valid(unsigned pwm_value);

void set_min_pwm(unsigned pwm_value);

void publish(struct actuator_outputs_s &actuator_outputs, float output);

/**
 * Print the correct usage.
 */
static void usage(const char *reason);

static void
usage(const char *reason)
{
	if (reason) {
		PX4_WARN("[motor_ramp] %s", reason);
	}

	PX4_WARN("[motor_ramp] usage:   motor_ramp <min_pwm> <ramp_time>");
	PX4_WARN("[motor_ramp] example: motor_ramp 1100 0.5\n");
}

/**
 * The motor_ramp app only briefly exists to start
 * the background job. The stack size assigned in the
 * Makefile does only apply to this management task.
 *
 * The actual stack size should be set in the call
 * to task_create().
 */
int motor_ramp_main(int argc, char *argv[])
{
	if (argc < 3) {
		usage("missing parameters");
		return 1;
	}

	if (_thread_running) {
		PX4_WARN("motor_ramp already running\n");
		/* this is not an error */
		return 0;
	}

	_min_pwm = atoi(argv[1]);

	if (!min_pwm_valid(_min_pwm)) {
		usage("min pwm not in range");
		return 1;
	}

	_ramp_time = strtof(argv[2], NULL);

	if (!(_ramp_time > 0)) {
		usage("ramp time must be greater than 0");
		return 1;
	}

	_thread_should_exit = false;
	_motor_ramp_task = px4_task_spawn_cmd("motor_ramp",
					     SCHED_DEFAULT,
					     SCHED_PRIORITY_DEFAULT,
					     2000,
					     motor_ramp_thread_main,
					     (argv) ? (char *const *)&argv[2] : (char *const *)NULL);
	return 0;

	usage("unrecognized command");
	return 1;
}

bool min_pwm_valid(unsigned pwm_value) {
	return pwm_value > 900 && pwm_value < 1300;
}

void set_min_pwm(unsigned pwm_value)
{
	int ret;
	unsigned servo_count;
	char *dev = PWM_OUTPUT0_DEVICE_PATH;
	int fd = px4_open(dev, 0);

	if (fd < 0) {PX4_WARN("[motor_ramp] can't open %s", dev);}

	ret = px4_ioctl(fd, PWM_SERVO_GET_COUNT, (unsigned long)&servo_count);
	struct pwm_output_values pwm_values;
	memset(&pwm_values, 0, sizeof(pwm_values));

	pwm_values.channel_count = servo_count;

	for (int i = 0; i < servo_count; i++) {
		pwm_values.values[i] = pwm_value;
	}

	ret = px4_ioctl(fd, PWM_SERVO_SET_MIN_PWM, (long unsigned int)&pwm_values);

	if (ret != OK) {PX4_WARN("[motor_ramp] failed setting min values");}

	px4_close(fd);
}

void publish(struct actuator_outputs_s &actuator_outputs, float output)
{
	//PX4_WARN("[motor_ramp] publish %f", (double)output);
	for (int i = 0; i < actuator_outputs_s::NUM_ACTUATOR_OUTPUTS; i++) {
		actuator_outputs.output[i] = output;
	}

	if (_actuator_outputs_pub == nullptr) {
		_actuator_outputs_pub = orb_advertise(ORB_ID(actuator_outputs), &actuator_outputs);

	} else {
		orb_publish(ORB_ID(actuator_outputs), _actuator_outputs_pub, &actuator_outputs);
	}
}

int motor_ramp_thread_main(int argc, char *argv[])
{
	PX4_WARN("[motor_ramp] starting");

	_thread_running = true;

	struct actuator_outputs_s actuator_outputs = {};
	publish(actuator_outputs, 0.0f);

	int ctrl_state_sub = orb_subscribe(ORB_ID(control_state));

	/* wakeup source */
	px4_pollfd_struct_t fds[1];

	/* Setup of loop */
	fds[0].fd = ctrl_state_sub;
	fds[0].events = POLLIN;

	float dt = 0.01f; // prevent division with 0
	float timer = 0.0f;
	hrt_abstime start = 0;
	hrt_abstime last_run = 0;

	enum RampState ramp_state = RAMP_INIT;
	float output = 0.0f;

	while (!_thread_should_exit) {
		if (last_run > 0) {
			dt = hrt_elapsed_time(&last_run) * 1e-6;

		} else {
			start = hrt_absolute_time();
		}

		last_run = hrt_absolute_time();
		timer = hrt_elapsed_time(&start) * 1e-6;

		/* wait for up to 500ms for data */
		int pret = px4_poll(&fds[0], (sizeof(fds) / sizeof(fds[0])), 100);

		/* timed out - periodic check for _task_should_exit, etc. */
		if (pret == 0) {
			continue;
		}

		/* this is undesirable but not much we can do - might want to flag unhappy status */
		if (pret < 0) {
			PX4_WARN("[motor_ramp] poll error %d", pret);
			continue;
		}

		switch (ramp_state) {
		case RAMP_INIT: {
				if (!min_pwm_valid(_min_pwm)) {
					_thread_should_exit = true;
					PX4_WARN("[motor_ramp] min pwm not in range %d", _min_pwm);
					break;
				}

				PX4_WARN("[motor_ramp] setting pwm min %d", _min_pwm);
				set_min_pwm(_min_pwm);
				ramp_state = RAMP_MIN;
				break;
			}

		case RAMP_MIN: {
				if (timer > 3.0f) {
					PX4_WARN("[motor_ramp] min set, starting ramp");
					start = hrt_absolute_time();
					ramp_state = RAMP_RAMP;
				}

				break;
			}

		case RAMP_RAMP: {
				output += dt / _ramp_time;

				if (output > 1.0f) {
					output = 1.0f;
					start = hrt_absolute_time();
					ramp_state = RAMP_WAIT;
					PX4_WARN("[motor_ramp] ramp finished, waiting");
				}

				publish(actuator_outputs, output);
				break;
			}

		case RAMP_WAIT: {
				if (timer > 3.0f) {
					_thread_should_exit = true;
					break;
				}

				break;
			}
		}
	}

	publish(actuator_outputs, 0.0f);

	PX4_WARN("[motor_ramp] exiting");

	_thread_running = false;

	return 0;
}
<|endoftext|>


<commit_before>#include <sstream>
#include <vector>

#include <hs/hs_compile.h>

#include "HyperscanEngine.h"

using namespace regexbench;

static int onMatch(unsigned int, unsigned long long,
                   unsigned long long, unsigned int, void *ctx) {
  size_t &nmatches = *static_cast<size_t *>(ctx);
  nmatches++;
  return 0;
}

HyperscanEngine::HyperscanEngine()
    : db(nullptr), scratch(nullptr),
      platform{HS_TUNE_FAMILY_GENERIC, 0, 0, 0} {
}

HyperscanEngine::~HyperscanEngine() {
  hs_free_database(db);
  hs_free_scratch(scratch);
}

void HyperscanEngine::compile(const std::vector<Rule> &rules) {
  std::vector<const char *> exps;
  std::vector<unsigned> flags;
  std::vector<unsigned> ids;
  for (const auto &rule : rules) {
    exps.push_back(rule.getRegexp().data());
    ids.push_back(static_cast<unsigned>(rule.getID()));
    unsigned flag = HS_FLAG_ALLOWEMPTY;
    if (rule.isSet(MOD_CASELESS)) flag |= HS_FLAG_CASELESS;
    if (rule.isSet(MOD_MULTILINE)) flag |= HS_FLAG_MULTILINE;
    if (rule.isSet(MOD_DOTALL)) flag |= HS_FLAG_DOTALL;
    flags.push_back(flag);
  }

  hs_compile_error_t *err;
  auto result = hs_compile_multi(exps.data(), flags.data(), ids.data(),
                                 static_cast<unsigned>(exps.size()),
                                 HS_MODE_BLOCK, &platform, &db, &err);
  if (result != HS_SUCCESS) {
    std::stringstream msg;
    msg << err->message << " (" << err->expression << ')';
    std::runtime_error error(msg.str());
    hs_free_compile_error(err);
    throw error;
  }

  result = hs_alloc_scratch(db, &scratch);
  if (result != HS_SUCCESS)
    throw std::bad_alloc();
}

size_t HyperscanEngine::match(const char *data, size_t len, size_t) {
  size_t nmatches = 0;
  hs_scan(db, data, static_cast<unsigned>(len), 0, scratch,
          onMatch, &nmatches);
  return nmatches > 0;
}
<commit_msg>Remove failed compliation rules for hyperscan<commit_after>#include <sstream>
#include <vector>

#include <hs/hs_compile.h>

#include "HyperscanEngine.h"

using namespace regexbench;

static int onMatch(unsigned int, unsigned long long,
                   unsigned long long, unsigned int, void *ctx) {
  size_t &nmatches = *static_cast<size_t *>(ctx);
  nmatches++;
  return 0;
}

HyperscanEngine::HyperscanEngine()
    : db(nullptr), scratch(nullptr),
      platform{HS_TUNE_FAMILY_GENERIC, 0, 0, 0} {
}

HyperscanEngine::~HyperscanEngine() {
  hs_free_database(db);
  hs_free_scratch(scratch);
}

void HyperscanEngine::compile(const std::vector<Rule> &rules) {
  std::vector<const char *> exps;
  std::vector<unsigned> flags;
  std::vector<unsigned> ids;
  for (const auto &rule : rules) {
    exps.push_back(rule.getRegexp().data());
    ids.push_back(static_cast<unsigned>(rule.getID()));
    unsigned flag = HS_FLAG_ALLOWEMPTY;
    if (rule.isSet(MOD_CASELESS)) flag |= HS_FLAG_CASELESS;
    if (rule.isSet(MOD_MULTILINE)) flag |= HS_FLAG_MULTILINE;
    if (rule.isSet(MOD_DOTALL)) flag |= HS_FLAG_DOTALL;
    flags.push_back(flag);
  }

  hs_compile_error_t *err;
  auto result = hs_compile_multi(exps.data(), flags.data(), ids.data(),
                                 static_cast<unsigned>(exps.size()),
                                 HS_MODE_BLOCK, &platform, &db, &err);
  // if multi rule compilation fails, compile a single rule at a time
  if (result != HS_SUCCESS) {
    exps.clear();
    ids.clear();
    flags.clear();
    for (const auto &rule : rules) {
      exps.push_back(rule.getRegexp().data());
      ids.push_back(static_cast<unsigned>(rule.getID()));
      unsigned flag = HS_FLAG_ALLOWEMPTY;
      if (rule.isSet(MOD_CASELESS)) flag |= HS_FLAG_CASELESS;
      if (rule.isSet(MOD_MULTILINE)) flag |= HS_FLAG_MULTILINE;
      if (rule.isSet(MOD_DOTALL)) flag |= HS_FLAG_DOTALL;
      if (hs_compile(rule.getRegexp().data(), flag,
                     HS_MODE_BLOCK, &platform, &db, &err) == HS_SUCCESS) {
        exps.push_back(rule.getRegexp().data());
        ids.push_back(static_cast<unsigned>(rule.getID()));
        flags.push_back(flag);
      } else {
        hs_free_compile_error(err);
      }
    }
  }

  result = hs_alloc_scratch(db, &scratch);
  if (result != HS_SUCCESS)
    throw std::bad_alloc();
}

size_t HyperscanEngine::match(const char *data, size_t len, size_t) {
  size_t nmatches = 0;
  hs_scan(db, data, static_cast<unsigned>(len), 0, scratch,
          onMatch, &nmatches);
  return nmatches > 0;
}
<|endoftext|>


<commit_before>/*
 * LEDMatrixDriver.cpp
 *
 *  Created on: 30.03.2017
 *      Author: Bartosz Bielawski
 */

#include "LEDMatrixDriver.hpp"
#include <Arduino.h>

LEDMatrixDriver::LEDMatrixDriver(uint8_t N, uint8_t ssPin, bool modRev_, uint8_t* frameBuffer_):
#ifdef USE_ADAFRUIT_GFX
	Adafruit_GFX(N*8, N),
#endif
	N(N),
	spiSettings(5000000, MSBFIRST, SPI_MODE0),
	modRev(modRev_),
	frameBuffer(frameBuffer_),
	selfAllocated(frameBuffer_ == nullptr),
	ssPin(ssPin)
{
	if (selfAllocated)
		frameBuffer = new uint8_t[N*8];

	clear();	// initally clear the buffer as the memory will not be initialized on reset (old content will be in memory yet)

	pinMode(ssPin, OUTPUT);
	digitalWrite(ssPin, 1);
	SPI.begin();
#ifdef ESP8266
	SPI.setHwCs(false);
#endif

	setEnabled(false);
	setIntensity(0);
	_sendCommand(LEDMatrixDriver::TEST);			//no test
	_sendCommand(LEDMatrixDriver::DECODE);			//no decode
	_sendCommand(LEDMatrixDriver::SCAN_LIMIT | 7);	//all lines
}

LEDMatrixDriver::LEDMatrixDriver(uint8_t N, uint8_t ssPin, uint8_t* frameBuffer_):
	LEDMatrixDriver(N, ssPin, false, frameBuffer_) {}

LEDMatrixDriver::~LEDMatrixDriver()
{
	if (selfAllocated)
		delete[] frameBuffer;
}

void LEDMatrixDriver::setPixel(int16_t x, int16_t y, bool enabled)
{
	uint8_t* p = _getBufferPtr(x,(modRev) ? 7 - y : y);
	if (!p)
		return;

	uint16_t b = (modRev) ? (x & 7) : 7 - (x & 7);		//bit

	if (enabled)
		*p |=  (1<<b);
	else
		*p &= ~(1<<b);
}

bool LEDMatrixDriver::getPixel(int16_t x, int16_t y) const
{
	uint8_t* p = _getBufferPtr(x,(modRev) ? 7 - y : y);
	if (!p)
		return false;

	uint16_t b = (modRev) ? (x & 7) : 7 - (x & 7);		//bit

	return *p & (1 << b);
}

void LEDMatrixDriver::setColumn(int16_t x, uint8_t value)
{
	//no need to check x, will be checked by setPixel
	for (uint8_t y = 0; y < 8; ++y)
	{
		setPixel(x, y, value & 1);
		value >>= 1;
	}
}

void LEDMatrixDriver::setEnabled(bool enabled)
{
	_sendCommand(ENABLE | (enabled ? 1: 0));
}

void LEDMatrixDriver::setIntensity(uint8_t level)
{
	_sendCommand(INTENSITY | level);
}

/**
 * Scan only digits 0..level.
 *
 * Beware: For level <=2 you must make sure that R_SET is appropriate
 * so the Maximum Segment Current is not higher than these numbers:
 * 		level	Max Current
 *		  0			10mA
 *		  1			20mA
 *		  2			30mA
 *
 * The command is sent to all drivers.
 */
void LEDMatrixDriver::setScanLimit(uint8_t level)
{
	_sendCommand(SCAN_LIMIT | level);
}

/**
 * Sets the Decode-Mode Register.
 *
 * Each set bit in mask enables "BCD Code B" decoding for a digit.
 * When "BCD Code B" is enabled the 4 lower bits of a digit are parsed:
 *    0-9  => The same digit is rendered
 *    10   => A dash (-) is rendered.
 *    11   => The letter "E" is rendered.
 *    12   => The letter "H" is rendered.
 *    13   => The letter "L" is rendered.
 *    14   => The letter "P" is rendered.
 *    15   => Blank display
 * Bit 7 (0x80) still controls the decimal point (dot).
 *
 * The command is sent to all drivers.
 */
void LEDMatrixDriver::setDecode(uint8_t mask)
{
	_sendCommand(DECODE | mask);
}

/**
 * Sets a digit to the specified value.
 * Digits are numbered 0..(8*N-1).
 * Digits 0..7 are in the first controller, digits 8..15 in the next, etc.
 */
void LEDMatrixDriver::setDigit(uint16_t digit, uint8_t value, bool dot)
{
	if (digit >= (8*N))
		return;

	// The frameBuffer is organized as 8 rows of N bytes.
	uint8_t row = digit % 8;
	uint8_t controller = digit / 8;

	frameBuffer[row * N + controller] = value | (dot ? 1<<7 : 0);
}

void LEDMatrixDriver::_sendCommand(uint16_t command)
{
	SPI.beginTransaction(spiSettings);
	digitalWrite(ssPin, 0);
	for (uint8_t i = 0; i < N; ++i)
	{
		SPI.transfer16(command);
	}
	digitalWrite(ssPin, 1);
	SPI.endTransaction();
}

void LEDMatrixDriver::_displayRow(uint8_t row)
{
	SPI.beginTransaction(spiSettings);
	digitalWrite(ssPin, 0);
	for (uint16_t d = 0; d < N; d++)
	{
		uint16_t cmd = ((row + 1) << 8) | frameBuffer[d + row*N];
		SPI.transfer16(cmd);
	}
	digitalWrite(ssPin, 1);
	SPI.endTransaction();
}

uint8_t* LEDMatrixDriver::_getBufferPtr(int16_t x, int16_t y) const
{
	if ((y >= 8) or (y < 0))
		return nullptr;
	if ((x >= (8*N)) or (x < 0))
		return nullptr;

	uint16_t B = x >> 3;		//byte

	return frameBuffer + y*N + B;
}

void LEDMatrixDriver::display()
{
	for (uint8_t y = 0; y < 8; y++)
	{
		_displayRow(y);
	}
}

void LEDMatrixDriver::scroll( scrollDirection direction )
{
	int cnt = 0;
	switch( direction )
	{
		case scrollDirection::scrollUp:
			cnt = 7*(N);	// moving 7 rows of N segments
			memmove(frameBuffer, frameBuffer + N, cnt);
			memset(frameBuffer+cnt, 0, N);		// Clear last row
			break;

		case scrollDirection::scrollDown:
			cnt = 7*N; // moving 7 rows of N segments
			memmove(frameBuffer+N, frameBuffer, cnt);
			memset(frameBuffer, 0, N);		// Clear first row
			break;

		case scrollDirection::scrollRight:
			// Scrolling right needs to be done by bit shifting every uint8_t in the frame buffer
			// Bits that overlap need to be carried to the next cell in a row
			for( int i = 8*N; i >= 0; i-- )
			{
				uint8_t n = frameBuffer[i] & 1;
				frameBuffer[i] >>= 1;
				if( (i+1)%N > 0 )
					frameBuffer[i+1] |= n<<7;
			}
			break;

		case scrollDirection::scrollLeft:
			// Scrolling left needs to be done by bit shifting every uint8_t in the frame buffer
			// Bits that overlap need to be carried to the prev cell in a row
			for( int i = 0; i < 8*N; i++ )
			{
				uint8_t n = frameBuffer[i] & B10000000;
				frameBuffer[i] <<= 1;
				if( i%N > 0 )
					frameBuffer[i-1] |= n>>7;
			}
			break;
	}
}
<commit_msg>Update LEDMatrixDriver.cpp<commit_after>/*
 * LEDMatrixDriver.cpp
 *
 *  Created on: 30.03.2017
 *      Author: Bartosz Bielawski
 */

#include "LEDMatrixDriver.hpp"
#include <Arduino.h>

LEDMatrixDriver::LEDMatrixDriver(uint8_t N, uint8_t ssPin, bool modRev_, uint8_t* frameBuffer_):
#ifdef USE_ADAFRUIT_GFX
	Adafruit_GFX(N*8, N),
#endif
	N(N),
	spiSettings(5000000, MSBFIRST, SPI_MODE0),
	modRev(modRev_),
	frameBuffer(frameBuffer_),
	selfAllocated(frameBuffer_ == nullptr),
	ssPin(ssPin)
{
	if (selfAllocated)
		frameBuffer = new uint8_t[N*8];

	clear();	// initally clear the buffer as the memory will not be initialized on reset (old content will be in memory yet)

	pinMode(ssPin, OUTPUT);
	digitalWrite(ssPin, 1);
	SPI.begin();
#ifdef ESP8266
	SPI.setHwCs(false);
#endif

	setEnabled(false);
	setIntensity(0);
	_sendCommand(LEDMatrixDriver::TEST);			//no test
	_sendCommand(LEDMatrixDriver::DECODE);			//no decode
	_sendCommand(LEDMatrixDriver::SCAN_LIMIT | 7);	//all lines
}

LEDMatrixDriver::LEDMatrixDriver(uint8_t N, uint8_t ssPin, uint8_t* frameBuffer_):
	LEDMatrixDriver(N, ssPin, false, frameBuffer_) {}

LEDMatrixDriver::~LEDMatrixDriver()
{
	if (selfAllocated)
		delete[] frameBuffer;
}

void LEDMatrixDriver::setPixel(int16_t x, int16_t y, bool enabled)
{
	uint8_t* p = _getBufferPtr(x,(modRev) ? 7 - y : y);
	if (!p)
		return;

	uint16_t b = (modRev) ? (x & 7) : 7 - (x & 7);		//bit

	if (enabled)
		*p |=  (1<<b);
	else
		*p &= ~(1<<b);
}

bool LEDMatrixDriver::getPixel(int16_t x, int16_t y) const
{
	uint8_t* p = _getBufferPtr(x,(modRev) ? 7 - y : y);
	if (!p)
		return false;

	uint16_t b = (modRev) ? (x & 7) : 7 - (x & 7);		//bit

	return *p & (1 << b);
}

void LEDMatrixDriver::setColumn(int16_t x, uint8_t value)
{
	//no need to check x, will be checked by setPixel
	for (uint8_t y = 0; y < 8; ++y)
	{
		setPixel(x, y, value & 1);
		value >>= 1;
	}
}

void LEDMatrixDriver::setEnabled(bool enabled)
{
	_sendCommand(ENABLE | (enabled ? 1: 0));
}

void LEDMatrixDriver::setIntensity(uint8_t level)
{
	_sendCommand(INTENSITY | level);
}

/**
 * Scan only digits 0..level.
 *
 * Beware: For level <=2 you must make sure that R_SET is appropriate
 * so the Maximum Segment Current is not higher than these numbers:
 * 		level	Max Current
 *		  0			10mA
 *		  1			20mA
 *		  2			30mA
 *
 * The command is sent to all drivers.
 */
void LEDMatrixDriver::setScanLimit(uint8_t level)
{
	_sendCommand(SCAN_LIMIT | level);
}

/**
 * Sets the Decode-Mode Register.
 *
 * Each set bit in mask enables "BCD Code B" decoding for a digit.
 * When "BCD Code B" is enabled the 4 lower bits of a digit are parsed:
 *    0-9  => The same digit is rendered
 *    10   => A dash (-) is rendered.
 *    11   => The letter "E" is rendered.
 *    12   => The letter "H" is rendered.
 *    13   => The letter "L" is rendered.
 *    14   => The letter "P" is rendered.
 *    15   => Blank display
 * Bit 7 (0x80) still controls the decimal point (dot).
 *
 * The command is sent to all drivers.
 */
void LEDMatrixDriver::setDecode(uint8_t mask)
{
	_sendCommand(DECODE | mask);
}

/**
 * Sets a digit to the specified value.
 * Digits are numbered 0..(8*N-1).
 * Digits 0..7 are in the first controller, digits 8..15 in the next, etc.
 */
void LEDMatrixDriver::setDigit(uint16_t digit, uint8_t value, bool dot)
{
	if (digit >= (8*N))
		return;

	// The frameBuffer is organized as 8 rows of N bytes.
	uint8_t row = digit % 8;
	uint8_t controller = digit / 8;

	frameBuffer[row * N + controller] = value | (dot ? 1<<7 : 0);
}

void LEDMatrixDriver::_sendCommand(uint16_t command)
{
	SPI.beginTransaction(spiSettings);
	digitalWrite(ssPin, 0);
	for (uint8_t i = 0; i < N; ++i)
	{
		SPI.transfer16(command);
	}
	digitalWrite(ssPin, 1);
	SPI.endTransaction();
}

void LEDMatrixDriver::_displayRow(uint8_t row)
{
	SPI.beginTransaction(spiSettings);
	digitalWrite(ssPin, 0);
	for (uint16_t d = 0; d < N; d++)
	{
		uint16_t cmd = ((row + 1) << 8) | frameBuffer[d + row*N];
		SPI.transfer16(cmd);
	}
	digitalWrite(ssPin, 1);
	SPI.endTransaction();
}

uint8_t* LEDMatrixDriver::_getBufferPtr(int16_t x, int16_t y) const
{
	if ((y >= 8) or (y < 0))
		return nullptr;
	if ((x >= (8*N)) or (x < 0))
		return nullptr;

	uint16_t B = x >> 3;		//byte

	return frameBuffer + y*N + B;
}

void LEDMatrixDriver::display()
{
	for (uint8_t y = 0; y < 8; y++)
	{
		_displayRow(y);
	}
}

void LEDMatrixDriver::scroll( scrollDirection direction )
{
	int cnt = 0;
	switch( direction )
	{
		case scrollDirection::scrollUp:
			cnt = 7*(N);	// moving 7 rows of N segments
			memmove(frameBuffer, frameBuffer + N, cnt);
			memset(frameBuffer+cnt, 0, N);		// Clear last row
			break;

		case scrollDirection::scrollDown:
			cnt = 7*N; // moving 7 rows of N segments
			memmove(frameBuffer+N, frameBuffer, cnt);
			memset(frameBuffer, 0, N);		// Clear first row
			break;

		case scrollDirection::scrollRight:
			// Scrolling right needs to be done by bit shifting every uint8_t in the frame buffer
			// Bits that overlap need to be carried to the next cell in a row
			for( int i = 8*N; i >= 0; i-- )
			{
				uint8_t n = frameBuffer[i] & 1;
				frameBuffer[i] >>= 1;
				if( (i+1)%N > 0 )
					frameBuffer[i+1] |= n<<7;
			}
			break;

		case scrollDirection::scrollLeft:
			// Scrolling left needs to be done by bit shifting every uint8_t in the frame buffer
			// Bits that overlap need to be carried to the prev cell in a row
			for( int i = 0; i < 8*N; i++ )
			{
				uint8_t n = frameBuffer[i] & B10000000;
				frameBuffer[i] <<= 1;
				if( i%N > 0 )
					frameBuffer[i-1] |= n>>7;
			}
			break;
	}
}
<|endoftext|>


<commit_before>
int main() { }
<commit_msg>simple speed test finished<commit_after>
/*
 * Copyright (c) 2015, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Author(s): Michael X. Grey <mxgrey@gatech.edu>
 *
 * Georgia Tech Graphics Lab and Humanoid Robotics Lab
 *
 * Directed by Prof. C. Karen Liu and Prof. Mike Stilman
 * <karenliu@cc.gatech.edu> <mstilman@cc.gatech.edu>
 *
 * This file is provided under the following "BSD-style" License:
 *   Redistribution and use in source and binary forms, with or
 *   without modification, are permitted provided that the following
 *   conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE.
 */

#include <chrono>

#include "dart/dynamics/Skeleton.h"
#include "dart/dynamics/DegreeOfFreedom.h"
#include "dart/simulation/World.h"
#include "dart/utils/SkelParser.h"
#include "dart/math/Helpers.h"
#include "dart/config.h"

double testForwardKinematicSpeed(dart::dynamics::Skeleton* skel,
                                 bool position=true,
                                 bool velocity=true,
                                 bool acceleration=true,
                                 size_t numTests=100000)
{
  if(NULL==skel)
    return 0;

  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();

  for(size_t i=0; i<numTests; ++i)
  {
    for(size_t i=0; i<skel->getNumDofs(); ++i)
    {
      dart::dynamics::DegreeOfFreedom* dof = skel->getDof(i);
      dof->setPosition( dart::math::random(
                          std::max(dof->getPositionLowerLimit(),-1.0),
                          std::min(dof->getPositionUpperLimit(), 1.0)) );
    }

    skel->computeForwardKinematics(position, velocity, acceleration);
  }

  end = std::chrono::system_clock::now();

  std::chrono::duration<double> elapsed_seconds = end-start;
  return elapsed_seconds.count();
}

std::vector<std::string> getSceneFiles()
{
  std::vector<std::string> scenes;
  scenes.push_back(DART_DATA_PATH"skel/test/chainwhipa.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/single_pendulum.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/single_pendulum_euler_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/single_pendulum_ball_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/double_pendulum.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/double_pendulum_euler_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/double_pendulum_ball_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/serial_chain_revolute_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/serial_chain_eulerxyz_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/serial_chain_ball_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/serial_chain_ball_joint_20.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/serial_chain_ball_joint_40.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/simple_tree_structure.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/simple_tree_structure_euler_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/simple_tree_structure_ball_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/tree_structure.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/tree_structure_euler_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/test/tree_structure_ball_joint.skel");
  scenes.push_back(DART_DATA_PATH"skel/fullbody1.skel");

  return scenes;
}

std::vector<dart::simulation::World*> getWorlds()
{
  std::vector<std::string> sceneFiles = getSceneFiles();
  std::vector<dart::simulation::World*> worlds;
  for(size_t i=0; i<sceneFiles.size(); ++i)
  {
    worlds.push_back(dart::utils::SkelParser::readWorld(sceneFiles[i]));
  }

  return worlds;
}

int main()
{
  std::vector<dart::simulation::World*> worlds = getWorlds();
  double totalTime = 0;
  for(size_t i=0; i<worlds.size(); ++i)
  {
    dart::simulation::World* world = worlds[i];
    totalTime += testForwardKinematicSpeed(world->getSkeleton(0));
  }

  std::cout << "Total time: " << totalTime << "s" << std::endl;
}
<|endoftext|>


<commit_before>#include <QScopedPointer>

#include <QtTest/QtTest>
#include "amqp_testcase.h"

#include "amqp_client.h"
#include "amqp_queue.h"
#include "amqp_exchange.h"

using namespace QAMQP;
class tst_QAMQPQueue : public TestCase
{
    Q_OBJECT
private Q_SLOTS:
    void init();
    void cleanup();

    void defaultExchange();
    void standardExchanges_data();
    void standardExchanges();

    void unnamed();
    void exclusiveAccess();
    void exclusiveRemoval();

    void remove();
    void removeIfUnused();
    void unbind();

private:    // disabled
    void removeIfEmpty();

private:
    QScopedPointer<Client> client;

};

void tst_QAMQPQueue::init()
{
    client.reset(new Client);
    client->connectToHost();
    QVERIFY(waitForSignal(client.data(), SIGNAL(connected())));
}

void tst_QAMQPQueue::cleanup()
{
    if (client->isConnected()) {
        client->disconnectFromHost();
        QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));
    }
}

void tst_QAMQPQueue::defaultExchange()
{
    Queue *queue = client->createQueue("test-default-exchange");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();

    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("test-default-exchange", "first message");
    QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
    Message message = queue->dequeue();
    QCOMPARE(message.payload(), QByteArray("first message"));
}

void tst_QAMQPQueue::standardExchanges_data()
{
    QTest::addColumn<QString>("exchange");
    QTest::newRow("amq.direct") << "amq.direct";
    QTest::newRow("amq.fanout") << "amq.fanout";
    QTest::newRow("amq.headers") << "amq.headers";
    QTest::newRow("amq.match") << "amq.match";
    QTest::newRow("amq.topic") << "amq.topic";
}

void tst_QAMQPQueue::standardExchanges()
{
    QFETCH(QString, exchange);

    QString queueName = QString("test-%1").arg(exchange);
    QString routingKey = QString("testRoutingKey-%1").arg(exchange);

    Queue *queue = client->createQueue(queueName);
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();   // required because AutoDelete will not delete if
                        // there was never a consumer

    queue->bind(exchange, routingKey);
    QVERIFY(waitForSignal(queue, SIGNAL(bound())));

    Exchange *defaultExchange = client->createExchange(exchange);
    defaultExchange->publish(routingKey, "test message");
    QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
    QCOMPARE(queue->dequeue().payload(), QByteArray("test message"));
}

void tst_QAMQPQueue::unnamed()
{
    Queue *queue = client->createQueue();
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();

    QVERIFY(!queue->name().isEmpty());
}

void tst_QAMQPQueue::exclusiveAccess()
{
    Queue *queue = client->createQueue("test-exclusive-queue");
    queue->declare(Queue::Exclusive);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));

    Client secondClient;
    secondClient.connectToHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
    Queue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
    passiveQueue->declare(Queue::Passive);
    QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(ChannelError))));
    QCOMPARE(passiveQueue->error(), Channel::ResourceLockedError);

    secondClient.disconnectFromHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}

void tst_QAMQPQueue::exclusiveRemoval()
{
    Queue *queue = client->createQueue("test-exclusive-queue");
    queue->declare(Queue::Exclusive);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    client.data()->disconnectFromHost();
    QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));

    // create a new client and try to access the queue that should
    // no longer exist
    Client secondClient;
    secondClient.connectToHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
    Queue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
    passiveQueue->declare(Queue::Passive);
    QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(ChannelError))));
    QCOMPARE(passiveQueue->error(), Channel::NotFoundError);
    secondClient.disconnectFromHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}

void tst_QAMQPQueue::remove()
{
    Queue *queue = client->createQueue("test-remove");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->remove(Queue::roIfEmpty|Queue::roIfUnused);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::removeIfUnused()
{
    Queue *queue = client->createQueue("test-remove-if-unused");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();

    queue->remove(Queue::roIfUnused);
    QVERIFY(waitForSignal(queue, SIGNAL(error(ChannelError))));
    QCOMPARE(queue->error(), Channel::PreconditionFailedError);
    QVERIFY(!queue->errorString().isEmpty());
}

void tst_QAMQPQueue::removeIfEmpty()
{
    // NOTE: this will work once I refactor messages to easily
    //       add propertis for e.g. persistence

    Queue *queue = client->createQueue("test-remove-if-empty");
    queue->declare(Queue::Durable);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();

    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("test-remove-if-empty", "first message");
    QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));

    queue->remove(Queue::roIfEmpty);
    QVERIFY(waitForSignal(queue, SIGNAL(error(ChannelError))));
    QCOMPARE(queue->error(), Channel::PreconditionFailedError);
    QVERIFY(!queue->errorString().isEmpty());
}

void tst_QAMQPQueue::unbind()
{
    Queue *queue = client->createQueue("test-unbind");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();   // required because AutoDelete will not delete if
                        // there was never a consumer

    queue->bind("amq.topic", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(bound())));
    queue->unbind("amq.topic", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(unbound())));
}

QTEST_MAIN(tst_QAMQPQueue)
#include "tst_qamqpqueue.moc"
<commit_msg>updated queue tests to include purge test, and reenable removeIfEmpty test<commit_after>#include <QScopedPointer>

#include <QtTest/QtTest>
#include "amqp_testcase.h"

#include "amqp_client.h"
#include "amqp_queue.h"
#include "amqp_exchange.h"

using namespace QAMQP;
class tst_QAMQPQueue : public TestCase
{
    Q_OBJECT
private Q_SLOTS:
    void init();
    void cleanup();

    void defaultExchange();
    void standardExchanges_data();
    void standardExchanges();

    void unnamed();
    void exclusiveAccess();
    void exclusiveRemoval();

    void remove();
    void removeIfUnused();
    void removeIfEmpty();
    void unbind();
    void purge();

private:
    QScopedPointer<Client> client;

};

void tst_QAMQPQueue::init()
{
    client.reset(new Client);
    client->connectToHost();
    QVERIFY(waitForSignal(client.data(), SIGNAL(connected())));
}

void tst_QAMQPQueue::cleanup()
{
    if (client->isConnected()) {
        client->disconnectFromHost();
        QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));
    }
}

void tst_QAMQPQueue::defaultExchange()
{
    Queue *queue = client->createQueue("test-default-exchange");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();

    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("test-default-exchange", "first message");
    QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
    Message message = queue->dequeue();
    QCOMPARE(message.payload(), QByteArray("first message"));
}

void tst_QAMQPQueue::standardExchanges_data()
{
    QTest::addColumn<QString>("exchange");
    QTest::newRow("amq.direct") << "amq.direct";
    QTest::newRow("amq.fanout") << "amq.fanout";
    QTest::newRow("amq.headers") << "amq.headers";
    QTest::newRow("amq.match") << "amq.match";
    QTest::newRow("amq.topic") << "amq.topic";
}

void tst_QAMQPQueue::standardExchanges()
{
    QFETCH(QString, exchange);

    QString queueName = QString("test-%1").arg(exchange);
    QString routingKey = QString("testRoutingKey-%1").arg(exchange);

    Queue *queue = client->createQueue(queueName);
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();   // required because AutoDelete will not delete if
                        // there was never a consumer

    queue->bind(exchange, routingKey);
    QVERIFY(waitForSignal(queue, SIGNAL(bound())));

    Exchange *defaultExchange = client->createExchange(exchange);
    defaultExchange->publish(routingKey, "test message");
    QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
    QCOMPARE(queue->dequeue().payload(), QByteArray("test message"));
}

void tst_QAMQPQueue::unnamed()
{
    Queue *queue = client->createQueue();
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();

    QVERIFY(!queue->name().isEmpty());
}

void tst_QAMQPQueue::exclusiveAccess()
{
    Queue *queue = client->createQueue("test-exclusive-queue");
    queue->declare(Queue::Exclusive);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));

    Client secondClient;
    secondClient.connectToHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
    Queue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
    passiveQueue->declare(Queue::Passive);
    QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(ChannelError))));
    QCOMPARE(passiveQueue->error(), Channel::ResourceLockedError);

    secondClient.disconnectFromHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}

void tst_QAMQPQueue::exclusiveRemoval()
{
    Queue *queue = client->createQueue("test-exclusive-queue");
    queue->declare(Queue::Exclusive);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    client.data()->disconnectFromHost();
    QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));

    // create a new client and try to access the queue that should
    // no longer exist
    Client secondClient;
    secondClient.connectToHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
    Queue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
    passiveQueue->declare(Queue::Passive);
    QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(ChannelError))));
    QCOMPARE(passiveQueue->error(), Channel::NotFoundError);
    secondClient.disconnectFromHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}

void tst_QAMQPQueue::remove()
{
    Queue *queue = client->createQueue("test-remove");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->remove(Queue::roIfEmpty|Queue::roIfUnused);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::removeIfUnused()
{
    Queue *queue = client->createQueue("test-remove-if-unused");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();

    queue->remove(Queue::roIfUnused);
    QVERIFY(waitForSignal(queue, SIGNAL(error(ChannelError))));
    QCOMPARE(queue->error(), Channel::PreconditionFailedError);
    QVERIFY(!queue->errorString().isEmpty());
}

void tst_QAMQPQueue::removeIfEmpty()
{
    // declare the queue and send messages to it
    Queue *queue = client->createQueue("test-remove-if-empty");
    queue->declare(Queue::Durable);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("test-remove-if-empty", "first message");

    // create a second client and try to delete the queue
    {
        Client secondClient;
        secondClient.connectToHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
        Queue *testDeleteQueue = secondClient.createQueue("test-remove-if-empty");
        testDeleteQueue->declare(Queue::Passive);
        QVERIFY(waitForSignal(testDeleteQueue, SIGNAL(declared())));

        testDeleteQueue->remove(Queue::roIfEmpty);
        QVERIFY(waitForSignal(testDeleteQueue, SIGNAL(error(ChannelError))));
        QCOMPARE(testDeleteQueue->error(), Channel::PreconditionFailedError);
        QVERIFY(!testDeleteQueue->errorString().isEmpty());

        secondClient.disconnectFromHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
    }

    // clean up queue
    queue->forceRemove();
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::unbind()
{
    Queue *queue = client->createQueue("test-unbind");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->consume();   // required because AutoDelete will not delete if
                        // there was never a consumer

    queue->bind("amq.topic", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(bound())));
    queue->unbind("amq.topic", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(unbound())));
}

void tst_QAMQPQueue::purge()
{
    Queue *queue = client->createQueue("test-purge");
    queue->declare(Queue::Durable);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("test-purge", "first message");
    defaultExchange->publish("test-purge", "second message");
    defaultExchange->publish("test-purge", "third message");

    // create second client to listen to messages and attempt purge
    {
        Client secondClient;
        secondClient.connectToHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
        Queue *testPurgeQueue = secondClient.createQueue("test-purge");
        testPurgeQueue->declare(Queue::Passive);
        QVERIFY(waitForSignal(testPurgeQueue, SIGNAL(declared())));

        QSignalSpy spy(testPurgeQueue, SIGNAL(purged(int)));
        testPurgeQueue->purge();
        QVERIFY(waitForSignal(testPurgeQueue, SIGNAL(purged(int))));
        QCOMPARE(spy.count(), 1);
        QCOMPARE(testPurgeQueue->size(), 0);
        QList<QVariant> arguments = spy.takeFirst();
        QCOMPARE(arguments.at(0).toInt(), 3);

        secondClient.disconnectFromHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
    }

    // clean up queue
    queue->forceRemove();
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

QTEST_MAIN(tst_QAMQPQueue)
#include "tst_qamqpqueue.moc"
<|endoftext|>