<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <cstring>

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QMetaObject>
#include <QMetaProperty>
#include <QtEndian>

#include <nitroshare/application.h>
#include <nitroshare/bundle.h>
#include <nitroshare/handler.h>
#include <nitroshare/handlerregistry.h>
#include <nitroshare/item.h>
#include <nitroshare/logger.h>
#include <nitroshare/message.h>
#include <nitroshare/packet.h>
#include <nitroshare/transfer.h>
#include <nitroshare/transport.h>

#include "transfer_p.h"

const QString MessageTag = "Transfer";

TransferPrivate::TransferPrivate(Transfer *parent, Application *application, Transport *transport,
                                 Bundle *bundle, Transfer::Direction direction)
    : QObject(parent),
      q(parent),
      application(application),
      transport(transport),
      bundle(bundle),
      protocolState(TransferHeader),
      direction(direction),
      state(Transfer::Connecting),
      progress(0),
      itemIndex(0),
      itemCount(bundle ? bundle->rowCount(QModelIndex()) : 0),
      bytesTransferred(0),
      bytesTotal(bundle ? bundle->totalSize() : 0),
      currentItem(nullptr),
      currentItemBytesTransferred(0),
      currentItemBytesTotal(0)
{
    // If sending data, trigger the first packet after connection
    if (direction == Transfer::Send) {
        connect(transport, &Transport::connected, this, &TransferPrivate::onPacketSent);
    }

    connect(transport, &Transport::packetReceived, this, &TransferPrivate::onPacketReceived);
    connect(transport, &Transport::packetSent, this, &TransferPrivate::onPacketSent);
    connect(transport, &Transport::error, this, &TransferPrivate::onError);
}

void TransferPrivate::sendTransferHeader()
{
    QJsonObject object{
        { "name", "unknown" },
        { "count", QString::number(bundle->rowCount(QModelIndex())) },
        { "size", QString::number(bundle->totalSize()) }
    };

    Packet packet(Packet::Json, QJsonDocument(object).toJson());
    transport->sendPacket(&packet);

    // The next packet will be an item header
    protocolState = ItemHeader;
}

void TransferPrivate::sendItemHeader()
{
    // Grab the next item and attempt to open it
    currentItem = bundle->index(itemIndex, 0).data(Qt::UserRole).value<Item*>();
    if (!currentItem->open(Item::Read)) {
        setError(tr("unable to open \"%1\" for reading").arg(currentItem->name()), true);
        return;
    }

    // Reset transfer stats
    currentItemBytesTransferred = 0;
    currentItemBytesTotal = currentItem->size();

    // Build a JSON object with all of the properties
    const QMetaObject *metaObj = currentItem->metaObject();
    QJsonObject object;

    for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) {
        const char *name = metaObj->property(i).name();
        object.insert(name, QJsonValue::fromVariant(currentItem->property(name)));
    }

    // Send the item header
    Packet packet(Packet::Json, QJsonDocument(object).toJson());
    transport->sendPacket(&packet);

    // If the item has a size, switch states; otherwise send the next item
    if (currentItemBytesTotal) {
        protocolState = ItemContent;
    } else {
        sendNext();
    }
}

void TransferPrivate::sendItemContent()
{
    QByteArray data = currentItem->read();
    Packet packet(Packet::Binary, data);
    transport->sendPacket(&packet);

    // Increment the number of bytes written to the socket
    bytesTransferred += data.length();
    currentItemBytesTransferred += data.length();

    updateProgress();

    // If the item completed, send the next one
    if (currentItemBytesTransferred >= currentItemBytesTotal) {
        sendNext();
    }
}

void TransferPrivate::sendNext()
{
    // Close the current item and increment the index
    currentItem->close();
    ++itemIndex;

    // If all items have been sent, move to the finished state and wait for
    // the success packet; otherwise, prepare to send the next item
    if (itemIndex == itemCount) {
        protocolState = Finished;
    } else {
        protocolState = ItemHeader;
    }
}

void TransferPrivate::processTransferHeader(Packet *packet)
{
    QJsonParseError error;
    QJsonObject object = QJsonDocument::fromJson(packet->content(), &error).object();
    if (error.error != QJsonParseError::NoError) {
        setError(QString("transfer header: %1").arg(error.errorString()), true);
        return;
    }

    // If the device name was provided, use it
    deviceName = object.value("name").toString();
    if (!deviceName.isEmpty()) {
        emit q->deviceNameChanged(deviceName);
    }

    // Strings must be used for 64-bit numbers
    itemCount = object.value("count").toString().toInt();
    bytesTotal = object.value("size").toString().toLongLong();

    // Prepare to receive the first item
    protocolState = ItemHeader;
}

void TransferPrivate::processItemHeader(Packet *packet)
{
    QJsonParseError error;
    QJsonObject object = QJsonDocument::fromJson(packet->content(), &error).object();
    if (error.error != QJsonParseError::NoError) {
        setError(QString("item header: %1").arg(error.errorString()), true);
        return;
    }

    // In order to maintain compatibility with legacy versions (which is very
    // desirable), if "type" is not in the object, assume "file" unless
    // "directory" is present (in which case, use that)
    QString type;
    if (object.contains("type")) {
        type = object.value("type").toString();
    } else {
        if (object.contains("directory")) {
            type = "directory";
        } else {
            type = "file";
        }
    }

    // Attempt to locate a handler for the type
    Handler *handler = application->handlerRegistry()->find(type);
    if (!handler) {
        setError(tr("unrecognized item type \"%1\"").arg(type), true);
        return;
    }

    // Use the handler to create an item and open it
    currentItem = handler->createItem(type, object.toVariantMap());
    currentItem->setParent(this);
    if (!currentItem->open(Item::Write)) {
        setError(tr("unable to open \"%1\" for writing").arg(currentItem->name()), true);
        return;
    }

    // Reset transfer stats
    currentItemBytesTransferred = 0;
    currentItemBytesTotal = currentItem->size();

    // If the item has a size, switch states; otherwise receive the next item
    if (currentItemBytesTotal) {
        protocolState = ItemContent;
    } else {
        processNext();
    }
}

void TransferPrivate::processItemContent(Packet *packet)
{
    currentItem->write(packet->content());

    // Add the number of bytes to the global & current item totals
    bytesTransferred += packet->content().size();
    currentItemBytesTransferred += packet->content().size();

    updateProgress();

    // If the current item is complete, advance to the next item or finish
    if (currentItemBytesTransferred >= currentItemBytesTotal) {
        processNext();
    }
}

void TransferPrivate::processNext()
{
    // Close & free the current item and increment the index
    currentItem->close();
    delete currentItem;
    ++itemIndex;

    // If there are no more items, send the success packet
    if (itemIndex == itemCount) {
        setSuccess(true);
    } else {
        protocolState = ItemHeader;
    }
}

void TransferPrivate::updateProgress()
{
    int newProgress = 0;
    if (bytesTotal) {
        newProgress = static_cast<int>(100.0 *
            static_cast<double>(bytesTransferred) /
            static_cast<double>(bytesTotal));
    }

    // Only update progress if it has actually changed
    if (newProgress != progress) {
        emit q->progressChanged(progress = newProgress);
    }
}

void TransferPrivate::setSuccess(bool send)
{
    if (send) {
        Packet packet(Packet::Success);
        transport->sendPacket(&packet);
    }

    emit q->stateChanged(state = Transfer::Succeeded);

    // Both peers should be aware that the transfer succeeded at this point
    transport->close();
}

void TransferPrivate::setError(const QString &message, bool send)
{
    application->logger()->log(new Message(
        Message::Error,
        MessageTag,
        message
    ));

    if (send) {
        Packet packet(Packet::Error, message.toUtf8());
        transport->sendPacket(&packet);
    }

    emit q->errorChanged(error = message);
    emit q->stateChanged(state = Transfer::Failed);

    // An error on either end necessitates the transport be closed
    transport->close();

    // The protocol dictates that the transfer is now "finished"
    protocolState = Finished;
}

void TransferPrivate::onPacketReceived(Packet *packet)
{
    // If an error packet is received, set the error and quit
    if (packet->type() == Packet::Error) {
        setError(packet->content());
        return;
    }

    if (direction == Transfer::Send) {

        // The only packet expected when sending items is the success packet
        // which indicates the receiver got all of the files
        if (protocolState == Finished && packet->type() == Packet::Success) {
            setSuccess();
            return;
        }

    } else {

        // Dispatch the packet to the appropriate method based on state
        switch (protocolState) {
        case TransferHeader:
            processTransferHeader(packet);
            return;
        case ItemHeader:
            processItemHeader(packet);
            return;
        case ItemContent:
            processItemContent(packet);
            return;
        }
    }

    // Any other packet was unexpected - assume this is an error
    setError(tr("protocol error - unexpected packet"), true);
}

void TransferPrivate::onPacketSent()
{
    // We don't care about sent packets when receiving data
    if (direction == Transfer::Receive) {
        return;
    }

    switch (protocolState) {
    case TransferHeader:
        sendTransferHeader();
    case ItemHeader:
        sendItemHeader();
    case ItemContent:
        sendItemContent();
    }
}

void TransferPrivate::onError(const QString &message)
{
    setError(message, true);
}

Transfer::Transfer(Application *application, Transport *transport, QObject *parent)
    : QObject(parent),
      d(new TransferPrivate(this, application, transport, nullptr, Transfer::Receive))
{
}

Transfer::Transfer(Application *application, Transport *transport, Bundle *bundle, QObject *parent)
    : QObject(parent),
      d(new TransferPrivate(this, application, transport, bundle, Transfer::Send))
{
}

Transfer::Direction Transfer::direction() const
{
    return d->direction;
}

Transfer::State Transfer::state() const
{
    return d->state;
}

int Transfer::progress() const
{
    return d->progress;
}

QString Transfer::deviceName() const
{
    return d->deviceName;
}

QString Transfer::error() const
{
    return d->error;
}

bool Transfer::isFinished() const
{
    return d->state == Failed || d->state == Succeeded;
}

void Transfer::cancel()
{
    d->setError(tr("transfer cancelled"), true);
}
<commit_msg>Send current device name with transfer.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <cstring>

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QMetaObject>
#include <QMetaProperty>
#include <QtEndian>

#include <nitroshare/application.h>
#include <nitroshare/bundle.h>
#include <nitroshare/handler.h>
#include <nitroshare/handlerregistry.h>
#include <nitroshare/item.h>
#include <nitroshare/logger.h>
#include <nitroshare/message.h>
#include <nitroshare/packet.h>
#include <nitroshare/transfer.h>
#include <nitroshare/transport.h>

#include "transfer_p.h"

const QString MessageTag = "Transfer";

TransferPrivate::TransferPrivate(Transfer *parent, Application *application, Transport *transport,
                                 Bundle *bundle, Transfer::Direction direction)
    : QObject(parent),
      q(parent),
      application(application),
      transport(transport),
      bundle(bundle),
      protocolState(TransferHeader),
      direction(direction),
      state(Transfer::Connecting),
      progress(0),
      itemIndex(0),
      itemCount(bundle ? bundle->rowCount(QModelIndex()) : 0),
      bytesTransferred(0),
      bytesTotal(bundle ? bundle->totalSize() : 0),
      currentItem(nullptr),
      currentItemBytesTransferred(0),
      currentItemBytesTotal(0)
{
    // If sending data, trigger the first packet after connection
    if (direction == Transfer::Send) {
        connect(transport, &Transport::connected, this, &TransferPrivate::onPacketSent);
    }

    connect(transport, &Transport::packetReceived, this, &TransferPrivate::onPacketReceived);
    connect(transport, &Transport::packetSent, this, &TransferPrivate::onPacketSent);
    connect(transport, &Transport::error, this, &TransferPrivate::onError);
}

void TransferPrivate::sendTransferHeader()
{
    QJsonObject object{
        { "name", application->deviceName() },
        { "count", QString::number(bundle->rowCount(QModelIndex())) },
        { "size", QString::number(bundle->totalSize()) }
    };

    Packet packet(Packet::Json, QJsonDocument(object).toJson());
    transport->sendPacket(&packet);

    // The next packet will be an item header
    protocolState = ItemHeader;
}

void TransferPrivate::sendItemHeader()
{
    // Grab the next item and attempt to open it
    currentItem = bundle->index(itemIndex, 0).data(Qt::UserRole).value<Item*>();
    if (!currentItem->open(Item::Read)) {
        setError(tr("unable to open \"%1\" for reading").arg(currentItem->name()), true);
        return;
    }

    // Reset transfer stats
    currentItemBytesTransferred = 0;
    currentItemBytesTotal = currentItem->size();

    // Build a JSON object with all of the properties
    const QMetaObject *metaObj = currentItem->metaObject();
    QJsonObject object;

    for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) {
        const char *name = metaObj->property(i).name();
        object.insert(name, QJsonValue::fromVariant(currentItem->property(name)));
    }

    // Send the item header
    Packet packet(Packet::Json, QJsonDocument(object).toJson());
    transport->sendPacket(&packet);

    // If the item has a size, switch states; otherwise send the next item
    if (currentItemBytesTotal) {
        protocolState = ItemContent;
    } else {
        sendNext();
    }
}

void TransferPrivate::sendItemContent()
{
    QByteArray data = currentItem->read();
    Packet packet(Packet::Binary, data);
    transport->sendPacket(&packet);

    // Increment the number of bytes written to the socket
    bytesTransferred += data.length();
    currentItemBytesTransferred += data.length();

    updateProgress();

    // If the item completed, send the next one
    if (currentItemBytesTransferred >= currentItemBytesTotal) {
        sendNext();
    }
}

void TransferPrivate::sendNext()
{
    // Close the current item and increment the index
    currentItem->close();
    ++itemIndex;

    // If all items have been sent, move to the finished state and wait for
    // the success packet; otherwise, prepare to send the next item
    if (itemIndex == itemCount) {
        protocolState = Finished;
    } else {
        protocolState = ItemHeader;
    }
}

void TransferPrivate::processTransferHeader(Packet *packet)
{
    QJsonParseError error;
    QJsonObject object = QJsonDocument::fromJson(packet->content(), &error).object();
    if (error.error != QJsonParseError::NoError) {
        setError(QString("transfer header: %1").arg(error.errorString()), true);
        return;
    }

    // If the device name was provided, use it
    deviceName = object.value("name").toString();
    if (!deviceName.isEmpty()) {
        emit q->deviceNameChanged(deviceName);
    }

    // Strings must be used for 64-bit numbers
    itemCount = object.value("count").toString().toInt();
    bytesTotal = object.value("size").toString().toLongLong();

    // Prepare to receive the first item
    protocolState = ItemHeader;
}

void TransferPrivate::processItemHeader(Packet *packet)
{
    QJsonParseError error;
    QJsonObject object = QJsonDocument::fromJson(packet->content(), &error).object();
    if (error.error != QJsonParseError::NoError) {
        setError(QString("item header: %1").arg(error.errorString()), true);
        return;
    }

    // In order to maintain compatibility with legacy versions (which is very
    // desirable), if "type" is not in the object, assume "file" unless
    // "directory" is present (in which case, use that)
    QString type;
    if (object.contains("type")) {
        type = object.value("type").toString();
    } else {
        if (object.contains("directory")) {
            type = "directory";
        } else {
            type = "file";
        }
    }

    // Attempt to locate a handler for the type
    Handler *handler = application->handlerRegistry()->find(type);
    if (!handler) {
        setError(tr("unrecognized item type \"%1\"").arg(type), true);
        return;
    }

    // Use the handler to create an item and open it
    currentItem = handler->createItem(type, object.toVariantMap());
    currentItem->setParent(this);
    if (!currentItem->open(Item::Write)) {
        setError(tr("unable to open \"%1\" for writing").arg(currentItem->name()), true);
        return;
    }

    // Reset transfer stats
    currentItemBytesTransferred = 0;
    currentItemBytesTotal = currentItem->size();

    // If the item has a size, switch states; otherwise receive the next item
    if (currentItemBytesTotal) {
        protocolState = ItemContent;
    } else {
        processNext();
    }
}

void TransferPrivate::processItemContent(Packet *packet)
{
    currentItem->write(packet->content());

    // Add the number of bytes to the global & current item totals
    bytesTransferred += packet->content().size();
    currentItemBytesTransferred += packet->content().size();

    updateProgress();

    // If the current item is complete, advance to the next item or finish
    if (currentItemBytesTransferred >= currentItemBytesTotal) {
        processNext();
    }
}

void TransferPrivate::processNext()
{
    // Close & free the current item and increment the index
    currentItem->close();
    delete currentItem;
    ++itemIndex;

    // If there are no more items, send the success packet
    if (itemIndex == itemCount) {
        setSuccess(true);
    } else {
        protocolState = ItemHeader;
    }
}

void TransferPrivate::updateProgress()
{
    int newProgress = 0;
    if (bytesTotal) {
        newProgress = static_cast<int>(100.0 *
            static_cast<double>(bytesTransferred) /
            static_cast<double>(bytesTotal));
    }

    // Only update progress if it has actually changed
    if (newProgress != progress) {
        emit q->progressChanged(progress = newProgress);
    }
}

void TransferPrivate::setSuccess(bool send)
{
    if (send) {
        Packet packet(Packet::Success);
        transport->sendPacket(&packet);
    }

    emit q->stateChanged(state = Transfer::Succeeded);

    // Both peers should be aware that the transfer succeeded at this point
    transport->close();
}

void TransferPrivate::setError(const QString &message, bool send)
{
    application->logger()->log(new Message(
        Message::Error,
        MessageTag,
        message
    ));

    if (send) {
        Packet packet(Packet::Error, message.toUtf8());
        transport->sendPacket(&packet);
    }

    emit q->errorChanged(error = message);
    emit q->stateChanged(state = Transfer::Failed);

    // An error on either end necessitates the transport be closed
    transport->close();

    // The protocol dictates that the transfer is now "finished"
    protocolState = Finished;
}

void TransferPrivate::onPacketReceived(Packet *packet)
{
    // If an error packet is received, set the error and quit
    if (packet->type() == Packet::Error) {
        setError(packet->content());
        return;
    }

    if (direction == Transfer::Send) {

        // The only packet expected when sending items is the success packet
        // which indicates the receiver got all of the files
        if (protocolState == Finished && packet->type() == Packet::Success) {
            setSuccess();
            return;
        }

    } else {

        // Dispatch the packet to the appropriate method based on state
        switch (protocolState) {
        case TransferHeader:
            processTransferHeader(packet);
            return;
        case ItemHeader:
            processItemHeader(packet);
            return;
        case ItemContent:
            processItemContent(packet);
            return;
        }
    }

    // Any other packet was unexpected - assume this is an error
    setError(tr("protocol error - unexpected packet"), true);
}

void TransferPrivate::onPacketSent()
{
    // We don't care about sent packets when receiving data
    if (direction == Transfer::Receive) {
        return;
    }

    switch (protocolState) {
    case TransferHeader:
        sendTransferHeader();
    case ItemHeader:
        sendItemHeader();
    case ItemContent:
        sendItemContent();
    }
}

void TransferPrivate::onError(const QString &message)
{
    setError(message, true);
}

Transfer::Transfer(Application *application, Transport *transport, QObject *parent)
    : QObject(parent),
      d(new TransferPrivate(this, application, transport, nullptr, Transfer::Receive))
{
}

Transfer::Transfer(Application *application, Transport *transport, Bundle *bundle, QObject *parent)
    : QObject(parent),
      d(new TransferPrivate(this, application, transport, bundle, Transfer::Send))
{
}

Transfer::Direction Transfer::direction() const
{
    return d->direction;
}

Transfer::State Transfer::state() const
{
    return d->state;
}

int Transfer::progress() const
{
    return d->progress;
}

QString Transfer::deviceName() const
{
    return d->deviceName;
}

QString Transfer::error() const
{
    return d->error;
}

bool Transfer::isFinished() const
{
    return d->state == Failed || d->state == Succeeded;
}

void Transfer::cancel()
{
    d->setError(tr("transfer cancelled"), true);
}
<|endoftext|>


<commit_before>/*
** transport-server.cpp
** Login : <hcuche@hcuche-de>
** Started on  Wed Jan 11 10:19:42 2012 Herve Cuche
** $Id$
**
** Author(s):
**  - Herve Cuche <hcuche@aldebaran-robotics.com>
**
** Copyright (C) 2012 Herve Cuche
*/

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <qi/log.hpp>
#include <cerrno>

#include <event2/util.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>

#ifdef _WIN32
 #include <winsock2.h> // for socket
 #include <WS2tcpip.h> // for socklen_t
#else
 #include <arpa/inet.h>
#endif

#include <qimessaging/transport_server.hpp>
#include <qimessaging/transport_socket.hpp>
#include <qimessaging/session.hpp>
#include "src/session_p.hpp"
#include "src/network_thread.hpp"
#include "src/transport_server_p.hpp"
#include "src/transport_socket_libevent_p.hpp"

namespace qi {
#define MAX_LINE 16384

void accept_cb(struct evconnlistener *listener,
               evutil_socket_t        fd,
               struct sockaddr       *QI_UNUSED(a),
               int                    QI_UNUSED(slen),
               void                  *p)
{
  TransportServerPrivate *_p = static_cast<TransportServerPrivate*>(p);
  _p->accept(fd, listener, p);
}

void TransportServerPrivate::accept(evutil_socket_t        fd,
                                    struct evconnlistener *listener,
                                    void                  *QI_UNUSED(context))
{
  struct event_base *base = evconnlistener_get_base(listener);

  qi::TransportSocket *ts = new qi::TransportSocket();
  ts->_p = new qi::TransportSocketLibEvent(ts, fd, base);
  connection.push(ts);

  tsi->newConnection();
}

bool TransportServerPrivate::start(struct event_base *base, const qi::Url &url)
{
  struct evconnlistener *listener;
  static struct sockaddr_storage listen_on_addr;
  memset(&listen_on_addr, 0, sizeof(listen_on_addr));
  int socklen = sizeof(listen_on_addr);
  struct sockaddr_in *sin = reinterpret_cast<struct sockaddr_in *>(&listen_on_addr);

  socklen = sizeof(struct sockaddr_in);
  sin->sin_port = htons(url.port());
  sin->sin_family = AF_INET;
  if ((sin->sin_addr.s_addr = inet_addr(url.host().c_str())) == INADDR_NONE)
  {
    qiLogError("qimessaging.transportserver") << "Provided IP is not valid" << std::endl;
    return false;
  }
  qiLogVerbose("qimessaging.transportserver") << "Starting server at " << url.str();
  listener = evconnlistener_new_bind(base,
                                     accept_cb,
                                     this,
                                     LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE,
                                     -1,
                                     (struct sockaddr*)&listen_on_addr,
                                     socklen);

  return listener != 0;
}

TransportServerInterface::~TransportServerInterface()
{
}

TransportServer::TransportServer()
{
  _p = new TransportServerPrivate();
}

TransportServer::~TransportServer()
{
  delete _p;
}

bool TransportServer::start(qi::Session *session, const qi::Url &url)
{
  struct event_base *base = session->_p->_networkThread->getEventBase();
  return _p->start(base, url);
}

TransportSocket *TransportServer::nextPendingConnection()
{
  if (!_p->connection.empty())
  {
    qi::TransportSocket *front = _p->connection.front();
    _p->connection.pop();
    return front;
  }

  return NULL;
}

void TransportServer::setCallbacks(TransportServerInterface *delegate)
{
  _p->tsi = delegate;
}

}
<commit_msg>Allow dynamic port allocation for TransportSocket.<commit_after>/*
** transport-server.cpp
** Login : <hcuche@hcuche-de>
** Started on  Wed Jan 11 10:19:42 2012 Herve Cuche
** $Id$
**
** Author(s):
**  - Herve Cuche <hcuche@aldebaran-robotics.com>
**
** Copyright (C) 2012 Herve Cuche
*/

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <qi/log.hpp>
#include <cerrno>

#include <event2/util.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>

#ifdef _WIN32
 #include <winsock2.h> // for socket
 #include <WS2tcpip.h> // for socklen_t
#else
 #include <arpa/inet.h>
#endif

#include <qimessaging/transport_server.hpp>
#include <qimessaging/transport_socket.hpp>
#include <qimessaging/session.hpp>
#include "src/session_p.hpp"
#include "src/network_thread.hpp"
#include "src/transport_server_p.hpp"
#include "src/transport_socket_libevent_p.hpp"

namespace qi {
#define MAX_LINE 16384

void accept_cb(struct evconnlistener *listener,
               evutil_socket_t        fd,
               struct sockaddr       *QI_UNUSED(a),
               int                    QI_UNUSED(slen),
               void                  *p)
{
  TransportServerPrivate *_p = static_cast<TransportServerPrivate*>(p);
  _p->accept(fd, listener, p);
}

void TransportServerPrivate::accept(evutil_socket_t        fd,
                                    struct evconnlistener *listener,
                                    void                  *QI_UNUSED(context))
{
  struct event_base *base = evconnlistener_get_base(listener);

  qi::TransportSocket *ts = new qi::TransportSocket();
  ts->_p = new qi::TransportSocketLibEvent(ts, fd, base);
  connection.push(ts);

  tsi->newConnection();
}

bool TransportServerPrivate::start(struct event_base *base, const qi::Url &url)
{
  struct evconnlistener *listener;
  static struct sockaddr_storage listen_on_addr;
  memset(&listen_on_addr, 0, sizeof(listen_on_addr));
  int socklen = sizeof(listen_on_addr);
  struct sockaddr_in *sin = reinterpret_cast<struct sockaddr_in *>(&listen_on_addr);

  socklen = sizeof(struct sockaddr_in);
  sin->sin_family = AF_INET;
  if ((sin->sin_addr.s_addr = inet_addr(url.host().c_str())) == INADDR_NONE)
  {
    qiLogError("qimessaging.transportserver") << "Provided IP is not valid" << std::endl;
    return false;
  }

  bool findPort = url.port() == 0;
  unsigned short port = url.port() == 0 ? 1 : url.port();

  do
  {
    sin->sin_port = htons(port);
    listener = evconnlistener_new_bind(base,
                                       accept_cb,
                                       this,
                                       LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE,
                                       -1,
                                       (struct sockaddr*)&listen_on_addr,
                                       socklen);

    if (!findPort || listener)
    {
      break;
    }

    port = qi::os::findAvailablePort(port);
  }
  while (port != 0);

  qiLogVerbose("qimessaging.transportserver") << "Starting server at "
                                              << url.host().c_str() << ":" << port;

  return listener != 0;
}

TransportServerInterface::~TransportServerInterface()
{
}

TransportServer::TransportServer()
{
  _p = new TransportServerPrivate();
}

TransportServer::~TransportServer()
{
  delete _p;
}

bool TransportServer::start(qi::Session *session, const qi::Url &url)
{
  struct event_base *base = session->_p->_networkThread->getEventBase();
  return _p->start(base, url);
}

TransportSocket *TransportServer::nextPendingConnection()
{
  if (!_p->connection.empty())
  {
    qi::TransportSocket *front = _p->connection.front();
    _p->connection.pop();
    return front;
  }

  return NULL;
}

void TransportServer::setCallbacks(TransportServerInterface *delegate)
{
  _p->tsi = delegate;
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "rpcserver.h"
#include "rpcclient.h"
#include "init.h"
#include "main.h"
#include "noui.h"
#include "ui_interface.h"
#include "util.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (http://www.bitcoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static bool fDaemon;

void DetectShutdownThread(boost::thread_group* threadGroup)
{
    bool fShutdown = ShutdownRequested();
    // Tell the main threads to shutdown.
    while (!fShutdown)
    {
        MilliSleep(200);
        fShutdown = ShutdownRequested();
    }
    if (threadGroup)
    {
        threadGroup->interrupt_all();
        threadGroup->join_all();
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
{
    boost::thread_group threadGroup;
    boost::thread* detectShutdownThread = NULL;

    bool fRet = false;
    try
    {
        //
        // Parameters
        //
        // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
        ParseParameters(argc, argv);
        if (!boost::filesystem::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
            return false;
        }
        try
        {
            ReadConfigFile(mapArgs, mapMultiArgs);
        } catch(std::exception &e) {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            return false;
        }
        // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause)
        if (!SelectParamsFromCommandLine()) {
            fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
            return false;
        }

        if (mapArgs.count("-?") || mapArgs.count("--help"))
        {
            // First part of help message is specific to bitcoind / RPC client
            std::string strUsage = _("Bitcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n\n" +
                _("Usage:") + "\n" +
                  "  bitcoind [options]                     " + _("Start Bitcoin Core Daemon") + "\n" +
                _("Usage (deprecated, use bitcoin-cli):") + "\n" +
                  "  bitcoind [options] <command> [params]  " + _("Send command to Bitcoin Core") + "\n" +
                  "  bitcoind [options] help                " + _("List commands") + "\n" +
                  "  bitcoind [options] help <command>      " + _("Get help for a command") + "\n";

            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
            strUsage += "\n" + HelpMessageCli(false);

            fprintf(stdout, "%s", strUsage.c_str());
            return false;
        }

        // Command-line RPC
        bool fCommandLine = false;
        for (int i = 1; i < argc; i++)
            if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "bitcoin:"))
                fCommandLine = true;

        if (fCommandLine)
        {
            int ret = CommandLineRPC(argc, argv);
            exit(ret);
        }
#ifndef WIN32
        fDaemon = GetBoolArg("-daemon", false);
        if (fDaemon)
        {
            fprintf(stdout, "Bitcoin server starting\n");

            // Daemonize
            pid_t pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
                return false;
            }
            if (pid > 0) // Parent process, pid is child process id
            {
                CreatePidFile(GetPidFile(), pid);
                return true;
            }
            // Child process falls through to rest of initialization

            pid_t sid = setsid();
            if (sid < 0)
                fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
        }
#endif
        SoftSetBoolArg("-server", true);

        detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup));
        fRet = AppInit2(threadGroup);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    if (!fRet)
    {
        if (detectShutdownThread)
            detectShutdownThread->interrupt();

        threadGroup.interrupt_all();
        // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
        // the startup-failure cases to make sure they don't result in a hang due to some
        // thread-blocking-waiting-for-another-thread-during-startup case
    }

    if (detectShutdownThread)
    {
        detectShutdownThread->join();
        delete detectShutdownThread;
        detectShutdownThread = NULL;
    }
    Shutdown();

    return fRet;
}

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

    bool fRet = false;

    // Connect bitcoind signal handlers
    noui_connect();

    fRet = AppInit(argc, argv);

    if (fRet && fDaemon)
        return 0;

    return (fRet ? 0 : 1);
}
<commit_msg>Remove fDaemon flag checking on return from main(), which is useless and looks really strange.<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "rpcserver.h"
#include "rpcclient.h"
#include "init.h"
#include "main.h"
#include "noui.h"
#include "ui_interface.h"
#include "util.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (http://www.bitcoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static bool fDaemon;

void DetectShutdownThread(boost::thread_group* threadGroup)
{
    bool fShutdown = ShutdownRequested();
    // Tell the main threads to shutdown.
    while (!fShutdown)
    {
        MilliSleep(200);
        fShutdown = ShutdownRequested();
    }
    if (threadGroup)
    {
        threadGroup->interrupt_all();
        threadGroup->join_all();
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
{
    boost::thread_group threadGroup;
    boost::thread* detectShutdownThread = NULL;

    bool fRet = false;
    try
    {
        //
        // Parameters
        //
        // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
        ParseParameters(argc, argv);
        if (!boost::filesystem::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
            return false;
        }
        try
        {
            ReadConfigFile(mapArgs, mapMultiArgs);
        } catch(std::exception &e) {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            return false;
        }
        // Check for -testnet or -regtest parameter (TestNet() calls are only valid after this clause)
        if (!SelectParamsFromCommandLine()) {
            fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
            return false;
        }

        if (mapArgs.count("-?") || mapArgs.count("--help"))
        {
            // First part of help message is specific to bitcoind / RPC client
            std::string strUsage = _("Bitcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n\n" +
                _("Usage:") + "\n" +
                  "  bitcoind [options]                     " + _("Start Bitcoin Core Daemon") + "\n" +
                _("Usage (deprecated, use bitcoin-cli):") + "\n" +
                  "  bitcoind [options] <command> [params]  " + _("Send command to Bitcoin Core") + "\n" +
                  "  bitcoind [options] help                " + _("List commands") + "\n" +
                  "  bitcoind [options] help <command>      " + _("Get help for a command") + "\n";

            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
            strUsage += "\n" + HelpMessageCli(false);

            fprintf(stdout, "%s", strUsage.c_str());
            return false;
        }

        // Command-line RPC
        bool fCommandLine = false;
        for (int i = 1; i < argc; i++)
            if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "bitcoin:"))
                fCommandLine = true;

        if (fCommandLine)
        {
            int ret = CommandLineRPC(argc, argv);
            exit(ret);
        }
#ifndef WIN32
        fDaemon = GetBoolArg("-daemon", false);
        if (fDaemon)
        {
            fprintf(stdout, "Bitcoin server starting\n");

            // Daemonize
            pid_t pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
                return false;
            }
            if (pid > 0) // Parent process, pid is child process id
            {
                CreatePidFile(GetPidFile(), pid);
                return true;
            }
            // Child process falls through to rest of initialization

            pid_t sid = setsid();
            if (sid < 0)
                fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
        }
#endif
        SoftSetBoolArg("-server", true);

        detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup));
        fRet = AppInit2(threadGroup);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    if (!fRet)
    {
        if (detectShutdownThread)
            detectShutdownThread->interrupt();

        threadGroup.interrupt_all();
        // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
        // the startup-failure cases to make sure they don't result in a hang due to some
        // thread-blocking-waiting-for-another-thread-during-startup case
    }

    if (detectShutdownThread)
    {
        detectShutdownThread->join();
        delete detectShutdownThread;
        detectShutdownThread = NULL;
    }
    Shutdown();

    return fRet;
}

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

    // Connect bitcoind signal handlers
    noui_connect();

    return (AppInit(argc, argv) ? 0 : 1);
}
<|endoftext|>


<commit_before>//=============================================================================================================
/**
 * @file     progressview.cpp
 * @author   Gabriel Motta <gbmotta@mgh.harvard.edu>
 * @since    0.1.6
 * @date     September, 2020
 *
 * @section  LICENSE
 *
 * Copyright (C) 2020, Gabriel B Motta. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *     * Redistributions of source code must retain the above copyright notice, this list 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.
 *     * Neither the name of MNE-CPP authors 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.
 *
 *
 * @brief    Definition of the ProgressView class.
 *
 */

//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "progressview.h"
#include "ui_progressview.h"

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace DISPLIB;

//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

ProgressView::ProgressView(bool bHorizontalMessage)
{
    (bHorizontalMessage) ? setHorizontal() : setVertical();

    m_pUi->m_progressBar->setMinimum(0);
    m_pUi->m_progressBar->setMaximum(0);
    m_pUi->m_progressBar->setValue(0);
    m_pUi->m_progressBar->setTextVisible(false);
    m_pUi->m_progressBar->setMaximumWidth(300);
}

//=============================================================================================================

ProgressView::~ProgressView()
{

}

//=============================================================================================================

void ProgressView::saveSettings()
{
}

//=============================================================================================================

void ProgressView::loadSettings()
{
}

//=============================================================================================================

void ProgressView::updateGuiMode(GuiMode mode)
{
    Q_UNUSED(mode);
}

//=============================================================================================================

void ProgressView::updateProcessingMode(ProcessingMode mode)
{
    Q_UNUSED(mode);
}

//=============================================================================================================

void ProgressView::setHorizontal()
{
    m_pUi->m_VerticalLabel->hide();
    m_pUi->m_HorizonatlLabel->show();
}

//=============================================================================================================

void ProgressView::setVertical()
{
    m_pUi->m_VerticalLabel->show();
    m_pUi->m_HorizonatlLabel->hide();
}

//=============================================================================================================

void ProgressView::setMessage(const QString &sMessage)
{
    m_pUi->m_VerticalLabel->setText(sMessage);
    m_pUi->m_HorizonatlLabel->setText(sMessage);
}

//=============================================================================================================

void ProgressView::updateProgress(int iPercentage, const QString& sMessage)
{
    if (m_pUi->m_progressBar->maximum() == 0){
        m_pUi->m_progressBar->setMaximum(100);
    }

    m_pUi->m_progressBar->setValue(iPercentage);

    setMessage(sMessage);
}
<commit_msg>FIX: create instance of abstract view and ui<commit_after>//=============================================================================================================
/**
 * @file     progressview.cpp
 * @author   Gabriel Motta <gbmotta@mgh.harvard.edu>
 * @since    0.1.6
 * @date     September, 2020
 *
 * @section  LICENSE
 *
 * Copyright (C) 2020, Gabriel B Motta. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *     * Redistributions of source code must retain the above copyright notice, this list 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.
 *     * Neither the name of MNE-CPP authors 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.
 *
 *
 * @brief    Definition of the ProgressView class.
 *
 */

//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "progressview.h"
#include "ui_progressview.h"

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace DISPLIB;

//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

ProgressView::ProgressView(bool bHorizontalMessage)
: AbstractView()
, m_pUi(new Ui::ProgressViewWidget)
{
    m_pUi->setupUi(this);

    (bHorizontalMessage) ? setHorizontal() : setVertical();

    m_pUi->m_progressBar->setMinimum(0);
    m_pUi->m_progressBar->setMaximum(0);
    m_pUi->m_progressBar->setValue(0);
    m_pUi->m_progressBar->setTextVisible(false);
    m_pUi->m_progressBar->setMaximumWidth(300);
}

//=============================================================================================================

ProgressView::~ProgressView()
{
    delete m_pUi;
}

//=============================================================================================================

void ProgressView::saveSettings()
{
}

//=============================================================================================================

void ProgressView::loadSettings()
{
}

//=============================================================================================================

void ProgressView::updateGuiMode(GuiMode mode)
{
    Q_UNUSED(mode);
}

//=============================================================================================================

void ProgressView::updateProcessingMode(ProcessingMode mode)
{
    Q_UNUSED(mode);
}

//=============================================================================================================

void ProgressView::setHorizontal()
{
    m_pUi->m_VerticalLabel->hide();
    m_pUi->m_HorizonatlLabel->show();
}

//=============================================================================================================

void ProgressView::setVertical()
{
    m_pUi->m_VerticalLabel->show();
    m_pUi->m_HorizonatlLabel->hide();
}

//=============================================================================================================

void ProgressView::setMessage(const QString &sMessage)
{
    m_pUi->m_VerticalLabel->setText(sMessage);
    m_pUi->m_HorizonatlLabel->setText(sMessage);
}

//=============================================================================================================

void ProgressView::updateProgress(int iPercentage, const QString& sMessage)
{
    if (m_pUi->m_progressBar->maximum() == 0){
        m_pUi->m_progressBar->setMaximum(100);
    }

    m_pUi->m_progressBar->setValue(iPercentage);

    setMessage(sMessage);
}
<|endoftext|>


<commit_before>/*
 * File:   NetworkWrapper.cpp
 * Author: daniel
 *
 * Created on April 1, 2015, 6:19 PM
 */

#include "NetworkWrapper.h"

NetworkWrapper::NetworkWrapper() : AudioProcessor(NULL)
{
}

NetworkWrapper::NetworkWrapper(const NetworkWrapper& orig) : AudioProcessor(orig)
{
}

NetworkWrapper::~NetworkWrapper()
{
    if(Socket != -1)
    {
        //close socket
         #ifdef __linux__
        shutdown(NetworkWrapper::Socket, SHUT_RDWR);
        #else
        closesocket(NetworkWrapper::Socket);
        #endif
    }
}

int NetworkWrapper::initializeNetwork()
{
    //dummy implementation, simply initialize socket
    int result = NetworkWrapper::startWinsock();
    if(result != 0)
    {
        return result;
    }
    result = NetworkWrapper::createSocket();
    if(result == -1)
    {
        return result;
    }
    //all okay
    return 0;
}

int NetworkWrapper::startWinsock()
{
    // Starting Winsock for Windows
    #ifndef __linux__
    WSADATA w;
    if(int result = WSAStartup(MAKEWORD(2,2), &w) != 0)
    {
        cerr << "Failed to start Winsock 2! Error #" << result << endl;
        return result;
    }
    #endif
    return 0;
}

int NetworkWrapper::createSocket()
{
    // AF_INET - creating an IPv4 based socket
    NetworkWrapper::Socket = socket(AF_INET, networkConfiguration.socketType, networkConfiguration.protocol);
    if(Socket == -1)
    {
        std::cerr << "Error on creating socket: " << errno << std::endl;
        return -1;
    }
    else
    {
        std::cout << "Socket created for " << (networkConfiguration.protocol == IPPROTO_TCP ? "TCP" : "UDP") << std::endl;
    }

    //6. connect

    //local address
    if(bind(Socket, &networkConfiguration.localAddr, sizeof(networkConfiguration.localAddr)) == -1)
    {
        std::cerr << "Error binding the socket: " << errno << std::endl;
        return -1;
    }
    else
    {
        std::cout << "Local port bound." << std::endl;
    }

    //remote address
    if(connect(Socket,&networkConfiguration.remoteAddr,sizeof(networkConfiguration.remoteAddr)) == -1)
    {
        std::cerr << "Error connection the socket:" << errno << std::endl;
        return -1;
    }
    else
    {
        std::cout << "Connection established." << std::endl;
    }

    return Socket;
}

<commit_msg>Quickfix: added std::<commit_after>/*
 * File:   NetworkWrapper.cpp
 * Author: daniel
 *
 * Created on April 1, 2015, 6:19 PM
 */

#include "NetworkWrapper.h"

NetworkWrapper::NetworkWrapper() : AudioProcessor(NULL)
{
}

NetworkWrapper::NetworkWrapper(const NetworkWrapper& orig) : AudioProcessor(orig)
{
}

NetworkWrapper::~NetworkWrapper()
{
    if(Socket != -1)
    {
        //close socket
         #ifdef __linux__
        shutdown(NetworkWrapper::Socket, SHUT_RDWR);
        #else
        closesocket(NetworkWrapper::Socket);
        #endif
    }
}

int NetworkWrapper::initializeNetwork()
{
    //dummy implementation, simply initialize socket
    int result = NetworkWrapper::startWinsock();
    if(result != 0)
    {
        return result;
    }
    result = NetworkWrapper::createSocket();
    if(result == -1)
    {
        return result;
    }
    //all okay
    return 0;
}

int NetworkWrapper::startWinsock()
{
    // Starting Winsock for Windows
    #ifndef __linux__
    WSADATA w;
    if(int result = WSAStartup(MAKEWORD(2,2), &w) != 0)
    {
        std::cerr << "Failed to start Winsock 2! Error #" << result << std::endl;
        return result;
    }
    #endif
    return 0;
}

int NetworkWrapper::createSocket()
{
    // AF_INET - creating an IPv4 based socket
    NetworkWrapper::Socket = socket(AF_INET, networkConfiguration.socketType, networkConfiguration.protocol);
    if(Socket == -1)
    {
        std::cerr << "Error on creating socket: " << errno << std::endl;
        return -1;
    }
    else
    {
        std::cout << "Socket created for " << (networkConfiguration.protocol == IPPROTO_TCP ? "TCP" : "UDP") << std::endl;
    }

    //6. connect

    //local address
    if(bind(Socket, &networkConfiguration.localAddr, sizeof(networkConfiguration.localAddr)) == -1)
    {
        std::cerr << "Error binding the socket: " << errno << std::endl;
        return -1;
    }
    else
    {
        std::cout << "Local port bound." << std::endl;
    }

    //remote address
    if(connect(Socket,&networkConfiguration.remoteAddr,sizeof(networkConfiguration.remoteAddr)) == -1)
    {
        std::cerr << "Error connection the socket:" << errno << std::endl;
        return -1;
    }
    else
    {
        std::cout << "Connection established." << std::endl;
    }

    return Socket;
}

<|endoftext|>


<commit_before>
#include "ODEIntegrators.h"
#include "Eigen/Core"
#include "CPstrings.h"
#include "Exceptions.h"
#include <algorithm>

bool ODEIntegrators::AdaptiveRK54(AbstractODEIntegrator &ode, double tstart, double tend, double hmin, double hmax, double eps_allowed, double step_relax)
{
    // Get the starting array of variables of integration
    std::vector<double> xold = ode.get_initial_array();
    const long N = static_cast<long>(xold.size());

    // Start at an index of 0
    int Itheta = 0;
    double t0 = tstart;
    double h = hmin;

    // Figure out if t is increasing or decreasing in the integration and set a flag
    bool forwards_integration = ((tend - tstart) > 0);
    // If backwards integration, flip the sign of the step
    if (!forwards_integration){
        h *= -1;
    }

    double max_error;

    std::vector<double> xnew1(N), xnew2(N), xnew3(N), xnew4(N), xnew5(N),
                        f1(N), f2(N), f3(N), f4(N), f5(N), f6(N),
                        error(N), xnew(N);

    // t is the independent variable here, where t takes on values in the bounded range [tmin,tmax]
    do{

        // Check for termination
        bool abort = ode.premature_termination();
        if (abort) { return abort; }

        bool stepAccepted = false, disableAdaptive = false;

        while (!stepAccepted)
        {

            // reset the flag
            disableAdaptive = false;

            // If the step would go beyond the end of the region of integration,
            // just take a step to the end of the region of integration
            if (forwards_integration && (t0 + h > tend)){
                disableAdaptive = true;
                h = tend - t0;
            }
            if (!forwards_integration && (t0 + h < tend)){
                disableAdaptive = true;
                h = t0 - tend;
            }

            ode.pre_step_callback();

            // We check stepAccepted again because if the derived class
            // sets the variable stepAccepted, we should not actually do the evaluation
            if (!stepAccepted)
            {

                Eigen::Map<Eigen::VectorXd> xold_w(&(xold[0]), N);

                if (std::abs(h) < hmin && !disableAdaptive){
                    // Step is too small, just use the minimum step size
                    h = (forwards_integration) ? hmin : -hmin;
                    disableAdaptive = true;
                }

                // Step 1: derivatives evaluated at old values
                ode.derivs(t0, xold, f1);

                // Call post derivative callback after the first derivative evaluation (which might cache values)
                ode.post_deriv_callback();

                Eigen::Map<Eigen::VectorXd> xnew1_w(&(xnew1[0]), N), f1_w(&(f1[0]),N);
                xnew1_w = xold_w+h*(1.0/5.0)*f1_w;

                ode.derivs(t0+1.0/5.0*h, xnew1, f2);
                Eigen::Map<Eigen::VectorXd> xnew2_w(&(xnew2[0]), N), f2_w(&(f2[0]),N);
                xnew2_w = xold_w+h*(+3.0/40.0*f1_w+9.0/40.0*f2_w);

                ode.derivs(t0+3.0/10.0*h, xnew2, f3);
                Eigen::Map<Eigen::VectorXd> xnew3_w(&(xnew3[0]), N), f3_w(&(f3[0]),N);
                xnew3_w = xold_w+h*(3.0/10.0*f1_w-9.0/10.0*f2_w+6.0/5.0*f3_w);

                ode.derivs(t0+3.0/5.0*h, xnew3, f4);
                Eigen::Map<Eigen::VectorXd> xnew4_w(&(xnew4[0]), N), f4_w(&(f4[0]),N);
                xnew4_w = xold_w+h*(-11.0/54.0*f1_w+5.0/2.0*f2_w-70.0/27.0*f3_w+35.0/27.0*f4_w);

                ode.derivs(t0+h, xnew4, f5);
                Eigen::Map<Eigen::VectorXd> xnew5_w(&(xnew5[0]), N), f5_w(&(f5[0]),N);
                xnew5_w = xold_w+h*(1631.0/55296*f1_w+175.0/512.0*f2_w+575.0/13824.0*f3_w+44275.0/110592.0*f4_w+253.0/4096.0*f5_w);

                // Updated values at the next step using 5-th order
                ode.derivs(t0+7.0/8.0*h, xnew5, f6);
                Eigen::Map<Eigen::VectorXd> xnew_w(&(xnew[0]),N), f6_w(&(f6[0]),N);
                xnew_w = xold_w + h*(37.0/378.0*f1_w + 250.0/621.0*f3_w + 125.0/594.0*f4_w + 512.0/1771.0*f6_w);

                Eigen::Map<Eigen::VectorXd> error_w(&(error[0]),N);
                error_w = h*(-277.0/64512.0*f1_w+6925.0/370944.0*f3_w-6925.0/202752.0*f4_w-277.0/14336.0*f5_w+277.0/7084.0*f6_w);

                max_error = error_w.norm();

                // If the error is too large, make the step size smaller and try
                // the step again
                if (disableAdaptive){
                    // Accept the step regardless of whether the error
                    // is too large or not
                    stepAccepted = true;
                }
                else{
                    if (max_error > eps_allowed){
                        // Take a smaller step next time, try again on this step
                        // But only if adaptive mode is on
                        h *= step_relax*pow(eps_allowed/max_error, 0.3);
                        stepAccepted = false;
                    }
                    else{
                        stepAccepted = true;
                    }
                }

            }
            else{
                std::cout << format("accepted");
            }
        }

        // Step has been accepted, update variables
        t0 += h;
        Itheta += 1;
        xold = xnew;

        ode.post_step_callback(t0, h, xnew);

        // The error is already below the threshold
        if (max_error < eps_allowed && disableAdaptive == false && max_error > 0){
            // Take a bigger step next time, since eps_allowed>max_error, but don't
            // let the steps get much larger too quickly
            h *= step_relax*pow(eps_allowed/max_error, 0.2);
        }

        // Constrain the step to not be too large
        if (forwards_integration) {
            h = std::min(h, hmax);
        }
        else {
            h = -std::min(std::abs(h), hmax);
        }

        // Overshot the end, oops...  That's an error
        if (forwards_integration && (t0 - tend > + 1e-3)){
            throw CoolProp::ValueError(format("t0 - tend [%g] > 1e-3", t0 - tend));
        }
        if (!forwards_integration && (t0 - tend < - 1e-3)) {
            throw CoolProp::ValueError(format("t0 - tend [%g] < -1e-3", t0 - tend));
        }
    }
    while (
            ((forwards_integration) && t0 < tend - 1e-10) ||
            ((!forwards_integration) && t0 > tend + 1e-10)
          );

    // No termination was requested
    return false;
}

#if defined(ENABLE_CATCH)
#include "catch.hpp"

TEST_CASE("Integrate y'=y","[ODEIntegrator]")
{
    class SimpleODEIntegrator : public ODEIntegrators::AbstractODEIntegrator{
    public:
        std::vector<double> t, h, y;

        virtual std::vector<double> get_initial_array() const{ return std::vector<double>(1,1); }

        virtual void pre_step_callback(){};

        virtual void post_deriv_callback(){};

        virtual void post_step_callback(double t, double h, std::vector<double> &y){
            this->t.push_back(t);
            this->h.push_back(h);
            this->y.push_back(y[0]);
        };

        virtual bool premature_termination(){ return false; };

        virtual void derivs(double t, std::vector<double> &y, std::vector<double> &yprime){ yprime[0] = y[0]; };
    };

    SimpleODEIntegrator simple;
    ODEIntegrators::AdaptiveRK54(simple, 0, 4, 1e-4, 0.5, 1e-7, 0.9);
    double yfinal_integration = simple.y[simple.y.size()-1];
    double tfinal_integration = simple.t[simple.t.size()-1];

    double yfinal_analytic = exp(4.0);
    double error = yfinal_integration/yfinal_analytic-1;

    CAPTURE(yfinal_analytic);
    CAPTURE(yfinal_integration);
    CAPTURE(tfinal_integration);
    CHECK(std::abs(error) < 1e-6);
    CHECK(std::abs(tfinal_integration-4) < 1e-10);
    int rr =0;
}
#endif
<commit_msg>Fix final step for ODE integration; closes #1672<commit_after>
#include "ODEIntegrators.h"
#include "Eigen/Core"
#include "CPstrings.h"
#include "Exceptions.h"
#include <algorithm>

bool ODEIntegrators::AdaptiveRK54(AbstractODEIntegrator &ode, double tstart, double tend, double hmin, double hmax, double eps_allowed, double step_relax)
{
    // Get the starting array of variables of integration
    std::vector<double> xold = ode.get_initial_array();
    const long N = static_cast<long>(xold.size());

    // Start at an index of 0
    int Itheta = 0;
    double t0 = tstart;
    double h = hmin;

    // Figure out if t is increasing or decreasing in the integration and set a flag
    bool forwards_integration = ((tend - tstart) > 0);
    // If backwards integration, flip the sign of the step
    if (!forwards_integration){
        h *= -1;
    }

    double max_error;

    std::vector<double> xnew1(N), xnew2(N), xnew3(N), xnew4(N), xnew5(N),
                        f1(N), f2(N), f3(N), f4(N), f5(N), f6(N),
                        error(N), xnew(N);

    // t is the independent variable here, where t takes on values in the bounded range [tmin,tmax]
    do{

        // Check for termination
        bool abort = ode.premature_termination();
        if (abort) { return abort; }

        bool stepAccepted = false, disableAdaptive = false;

        while (!stepAccepted)
        {

            // reset the flag
            disableAdaptive = false;

            // If the step would go beyond the end of the region of integration,
            // just take a step to the end of the region of integration
            if (forwards_integration && (t0 + h > tend)){
                disableAdaptive = true;
                h = tend - t0;
            }
            if (!forwards_integration && (t0 + h < tend)){
                disableAdaptive = true;
                h = tend - t0;
            }

            ode.pre_step_callback();

            // We check stepAccepted again because if the derived class
            // sets the variable stepAccepted, we should not actually do the evaluation
            if (!stepAccepted)
            {

                Eigen::Map<Eigen::VectorXd> xold_w(&(xold[0]), N);

                if (std::abs(h) < hmin && !disableAdaptive){
                    // Step is too small, just use the minimum step size
                    h = (forwards_integration) ? hmin : -hmin;
                    disableAdaptive = true;
                }

                // Step 1: derivatives evaluated at old values
                ode.derivs(t0, xold, f1);

                // Call post derivative callback after the first derivative evaluation (which might cache values)
                ode.post_deriv_callback();

                Eigen::Map<Eigen::VectorXd> xnew1_w(&(xnew1[0]), N), f1_w(&(f1[0]),N);
                xnew1_w = xold_w+h*(1.0/5.0)*f1_w;

                ode.derivs(t0+1.0/5.0*h, xnew1, f2);
                Eigen::Map<Eigen::VectorXd> xnew2_w(&(xnew2[0]), N), f2_w(&(f2[0]),N);
                xnew2_w = xold_w+h*(+3.0/40.0*f1_w+9.0/40.0*f2_w);

                ode.derivs(t0+3.0/10.0*h, xnew2, f3);
                Eigen::Map<Eigen::VectorXd> xnew3_w(&(xnew3[0]), N), f3_w(&(f3[0]),N);
                xnew3_w = xold_w+h*(3.0/10.0*f1_w-9.0/10.0*f2_w+6.0/5.0*f3_w);

                ode.derivs(t0+3.0/5.0*h, xnew3, f4);
                Eigen::Map<Eigen::VectorXd> xnew4_w(&(xnew4[0]), N), f4_w(&(f4[0]),N);
                xnew4_w = xold_w+h*(-11.0/54.0*f1_w+5.0/2.0*f2_w-70.0/27.0*f3_w+35.0/27.0*f4_w);

                ode.derivs(t0+h, xnew4, f5);
                Eigen::Map<Eigen::VectorXd> xnew5_w(&(xnew5[0]), N), f5_w(&(f5[0]),N);
                xnew5_w = xold_w+h*(1631.0/55296*f1_w+175.0/512.0*f2_w+575.0/13824.0*f3_w+44275.0/110592.0*f4_w+253.0/4096.0*f5_w);

                // Updated values at the next step using 5-th order
                ode.derivs(t0+7.0/8.0*h, xnew5, f6);
                Eigen::Map<Eigen::VectorXd> xnew_w(&(xnew[0]),N), f6_w(&(f6[0]),N);
                xnew_w = xold_w + h*(37.0/378.0*f1_w + 250.0/621.0*f3_w + 125.0/594.0*f4_w + 512.0/1771.0*f6_w);

                Eigen::Map<Eigen::VectorXd> error_w(&(error[0]),N);
                error_w = h*(-277.0/64512.0*f1_w+6925.0/370944.0*f3_w-6925.0/202752.0*f4_w-277.0/14336.0*f5_w+277.0/7084.0*f6_w);

                max_error = error_w.norm();

                // If the error is too large, make the step size smaller and try
                // the step again
                if (disableAdaptive){
                    // Accept the step regardless of whether the error
                    // is too large or not
                    stepAccepted = true;
                }
                else{
                    if (max_error > eps_allowed){
                        // Take a smaller step next time, try again on this step
                        // But only if adaptive mode is on
                        h *= step_relax*pow(eps_allowed/max_error, 0.3);
                        stepAccepted = false;
                    }
                    else{
                        stepAccepted = true;
                    }
                }

            }
            else{
                std::cout << format("accepted");
            }
        }

        // Step has been accepted, update variables
        t0 += h;
        Itheta += 1;
        xold = xnew;

        ode.post_step_callback(t0, h, xnew);

        // The error is already below the threshold
        if (max_error < eps_allowed && disableAdaptive == false && max_error > 0){
            // Take a bigger step next time, since eps_allowed>max_error, but don't
            // let the steps get much larger too quickly
            h *= step_relax*pow(eps_allowed/max_error, 0.2);
        }

        // Constrain the step to not be too large
        if (forwards_integration) {
            h = std::min(h, hmax);
        }
        else {
            h = -std::min(std::abs(h), hmax);
        }

        // Overshot the end, oops...  That's an error
        if (forwards_integration && (t0 - tend > + 1e-3)){
            throw CoolProp::ValueError(format("t0 - tend [%g] > 1e-3", t0 - tend));
        }
        if (!forwards_integration && (t0 - tend < - 1e-3)) {
            throw CoolProp::ValueError(format("t0 - tend [%g] < -1e-3", t0 - tend));
        }
    }
    while (
            ((forwards_integration) && t0 < tend - 1e-10) ||
            ((!forwards_integration) && t0 > tend + 1e-10)
          );

    // No termination was requested
    return false;
}

#if defined(ENABLE_CATCH)
#include "catch.hpp"

TEST_CASE("Integrate y'=y","[ODEIntegrator]")
{
    class SimpleODEIntegrator : public ODEIntegrators::AbstractODEIntegrator{
    public:
        std::vector<double> t, h, y;

        virtual std::vector<double> get_initial_array() const{ return std::vector<double>(1,1); }

        virtual void pre_step_callback(){};

        virtual void post_deriv_callback(){};

        virtual void post_step_callback(double t, double h, std::vector<double> &y){
            this->t.push_back(t);
            this->h.push_back(h);
            this->y.push_back(y[0]);
        };

        virtual bool premature_termination(){ return false; };

        virtual void derivs(double t, std::vector<double> &y, std::vector<double> &yprime){ yprime[0] = y[0]; };
    };

    SimpleODEIntegrator simple;
    ODEIntegrators::AdaptiveRK54(simple, 0, 4, 1e-4, 0.5, 1e-7, 0.9);
    double yfinal_integration = simple.y[simple.y.size()-1];
    double tfinal_integration = simple.t[simple.t.size()-1];

    double yfinal_analytic = exp(4.0);
    double error = yfinal_integration/yfinal_analytic-1;

    CAPTURE(yfinal_analytic);
    CAPTURE(yfinal_integration);
    CAPTURE(tfinal_integration);
    CHECK(std::abs(error) < 1e-6);
    CHECK(std::abs(tfinal_integration-4) < 1e-10);
    int rr =0;
}
#endif
<|endoftext|>


<commit_before>#include "application.h"
#include <inttypes.h>

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);
SerialLogHandler traceLog(LOG_LEVEL_TRACE);

static TCPServer tcpServer = TCPServer(6666);
static TCPClient tcpClient;

// Toggle LED pin to see that application loop is not blocked.
// You could use D7 when testing with a Photon.
// I'm using another pin here, because D7 is one of the SWD pins used by the debugger
const int LED_PIN = P1S0;

enum tcp_state_enum {
    RUNNING_FINE,
    NEEDS_TO_STOP,
    STOPPED,
    ALLOWED_TO_RESTART,
};

volatile uint8_t tcp_state;

void stopTcp(){
    tcpServer.stop();
    tcpClient.stop();
    Serial.print("TCP server stopped\n");
}

void startTcp(){
    tcpServer.begin();
    Serial.print("TCP server started\n");
}

void handle_network_events(system_event_t event, int param){
    static int cloud_connection_tries = 0;
    switch(param){
    case network_status_powering_on:
        break;
    case network_status_on:
        break;
    case network_status_powering_off:
        break;
    case network_status_off:
        break;
    case network_status_connecting:
        // set a flag to restart the TCP server, outside of the system thread
        // restarting it here doesn't work
        // leaving it running doesn't work
        if(tcp_state != tcp_state_enum::STOPPED){
            tcp_state = tcp_state_enum::NEEDS_TO_STOP;
        }
        break;
    case network_status_connected:
        tcp_state = tcp_state_enum::ALLOWED_TO_RESTART;
        break;
    default:
        break;
    }
    Serial.printf("network event %d\n", param);
}

void handle_cloud_events(system_event_t event, int param){
    switch(param){
    case cloud_status_connecting:
        break;
    case cloud_status_connected:
        break;
    case cloud_status_disconnecting:
        break;
    case cloud_status_disconnected:
        break;
    default:
        break;
    }
}

// return time that has passed since timeStamp, take overflow into account
system_tick_t timeSince(system_tick_t previousTime) {
    system_tick_t currentTime = millis();
    if(currentTime>=previousTime){
        return currentTime - previousTime;
    }
    else{
        // overflow has occurred
        return (currentTime + 1440000) - (previousTime +1440000); // add a day to both for calculation
    }
}

void setup() {
    System.set(SYSTEM_CONFIG_SOFTAP_PREFIX, "BREWPI");
    System.disable(SYSTEM_FLAG_RESET_NETWORK_ON_CLOUD_ERRORS);
    Serial.begin(115200);
    pinMode(LED_PIN, OUTPUT);

    WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);
    Particle.connect();

    System.on(network_status, handle_network_events);
    System.on(cloud_status, handle_cloud_events);
    tcp_state = tcp_state_enum::ALLOWED_TO_RESTART;
}

void loop() {
    static system_tick_t last_update = millis();
    static system_tick_t lastLedToggle = millis();

    if(WiFi.RSSI() >= 0){
        // WiFi is in error state, stop TCP server
        if(tcp_state != tcp_state_enum::STOPPED){
            tcp_state = tcp_state_enum::NEEDS_TO_STOP;
        }
    }

    switch(tcp_state){
        case tcp_state_enum::RUNNING_FINE:
            if(!WiFi.ready()){
                // check in case WiFi is not ready but the system events didn't trigger the correct state
                tcp_state = tcp_state_enum::NEEDS_TO_STOP;
            }
            break;
        case tcp_state_enum::NEEDS_TO_STOP:
            Serial.print("Stopping TCP\n");
            stopTcp();
            tcp_state = tcp_state_enum::STOPPED;
            break;
        case tcp_state_enum::STOPPED:
            break;
        case tcp_state_enum::ALLOWED_TO_RESTART:
            Serial.print("Restarting TCP\n");
            startTcp();
            tcp_state = tcp_state_enum::RUNNING_FINE; // assume it is running fine afterwards
            break;

    }

    if(tcp_state == tcp_state_enum::RUNNING_FINE){
        if(tcpClient.status()){
            bool noErrors = true;
            while (noErrors && tcpClient.available() > 0) {
                int received = tcpClient.read();
                switch(received){
                case ' ':
                case '\n':
                case '\r':
                    break;
                case 't':
                {
                    size_t result = tcpClient.write("toc"); // send toc back over tcp
                    Serial.printf("hw->py: toc (%d bytes sent) \n", result); // confirm toc sent over tcp
                }
                    break;
                default:
                    if(received < 0){
                        Serial.printf("Receive error: %d\n", received); // confirm toc sent over tcp
                        noErrors = false;
                    }
                    else{
                        Serial.printf("py->hw: %c\n", received); // confirm character received from tcp
                    }
                    break;
                }
            }
        }
        // listen for a new client, drop the old one if a new client arrives
        TCPClient newClient = tcpServer.available();
        if(newClient) {
           Serial.print("New TCP client\n");
           tcpClient.write("New TCP client arrived, dropping you."); // stop old client
           tcpClient.stop(); // stop old client
           tcpClient = newClient;
        }
    }

    // print status on serial every second
    if(timeSince(last_update) >= 1000UL ) {
        last_update = millis();
        bool wifiReady = WiFi.ready();
        IPAddress ip = WiFi.localIP();
        int signal = WiFi.RSSI();
        int clientConnected = tcpClient.connected();
        Serial.printf(
                "WiFi.ready(): %d\t\t"
                "IP: %d.%d.%d.%d\t\t"
                "RSSI: %d\t\t"
                "TCP client connected: %d\t\t"
                "millis(): %" PRIu32 "\n",
                wifiReady,
                ip[0],ip[1],ip[2],ip[3],
                signal,
                clientConnected,
                last_update);
    }

    if(timeSince(lastLedToggle) >= 200UL ) {
        lastLedToggle = millis();
        static bool ledOn = true;
        ledOn = !ledOn;
        digitalWrite(LED_PIN, ledOn);
    }
    Particle.process();
}
<commit_msg>Simplified handling of TCP server now that WiFi.ready() is working as expected<commit_after>#include "application.h"
#include <inttypes.h>

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);
SerialLogHandler traceLog(LOG_LEVEL_TRACE);

static TCPServer tcpServer = TCPServer(6666);
static TCPClient tcpClient;
bool tcpServerRunning;

// Toggle LED pin to see that application loop is not blocked.
// You could use D7 when testing with a Photon.
// I'm using another pin here, because D7 is one of the SWD pins used by the debugger
const int LED_PIN = P1S0;

void stopTcp(){
    tcpServer.stop();
    tcpClient.stop();
    tcpServerRunning = false;
    Serial.print("TCP server stopped\n");
}

void startTcp(){
    tcpServer.begin();
    tcpServerRunning = true;
    Serial.print("TCP server started\n");
}

void handle_network_events(system_event_t event, int param){
    switch(param){
    case network_status_powering_on:
        break;
    case network_status_on:
        break;
    case network_status_powering_off:
        break;
    case network_status_off:
        break;
    case network_status_connecting:
        break;
    case network_status_connected:
        break;
    default:
        break;
    }
    Serial.printf("network event %d\n", param);
}

void handle_cloud_events(system_event_t event, int param){
    switch(param){
    case cloud_status_connecting:
        break;
    case cloud_status_connected:
        break;
    case cloud_status_disconnecting:
        break;
    case cloud_status_disconnected:
        break;
    default:
        break;
    }
    Serial.printf("cloud event %d\n", param);
}

// return time that has passed since timeStamp, take overflow into account
system_tick_t timeSince(system_tick_t previousTime) {
    system_tick_t currentTime = millis();
    if(currentTime>=previousTime){
        return currentTime - previousTime;
    }
    else{
        // overflow has occurred
        return (currentTime + 1440000) - (previousTime +1440000); // add a day to both for calculation
    }
}

void setup() {
    System.set(SYSTEM_CONFIG_SOFTAP_PREFIX, "BREWPI");
    System.disable(SYSTEM_FLAG_RESET_NETWORK_ON_CLOUD_ERRORS);
    Serial.begin(115200);
    pinMode(LED_PIN, OUTPUT);

    WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);
    Particle.connect();

    System.on(network_status, handle_network_events);
    System.on(cloud_status, handle_cloud_events);
}

void loop() {
    static system_tick_t last_update = millis();
    static system_tick_t lastLedToggle = millis();

    if(!WiFi.ready()){
        // WiFi is in error state, stop TCP server
        if(tcpServerRunning){
            stopTcp();
        }
    }
    else{
    	if(!tcpServerRunning){
			startTcp();
		}
    }

    if(tcpServerRunning){
        if(tcpClient.status()){
            bool noErrors = true;
            while (noErrors && tcpClient.available() > 0) {
                int received = tcpClient.read();
                switch(received){
                case ' ':
                case '\n':
                case '\r':
                    break;
                case 't':
                {
                    size_t result = tcpClient.write("toc"); // send toc back over tcp
                    Serial.printf("hw->py: toc (%d bytes sent) \n", result); // confirm toc sent over tcp
                }
                    break;
                default:
                    if(received < 0){
                        Serial.printf("Receive error: %d\n", received); // confirm toc sent over tcp
                        noErrors = false;
                    }
                    else{
                        Serial.printf("py->hw: %c\n", received); // confirm character received from tcp
                    }
                    break;
                }
            }
        }
        // listen for a new client, drop the old one if a new client arrives
        TCPClient newClient = tcpServer.available();
        if(newClient) {
           Serial.print("New TCP client\n");
           tcpClient.write("New TCP client arrived, dropping you."); // stop old client
           tcpClient.stop(); // stop old client
           tcpClient = newClient;
        }
    }

    // print status on serial every second
    if(timeSince(last_update) >= 1000UL ) {
        last_update = millis();
        bool wifiReady = WiFi.ready();
        IPAddress ip = WiFi.localIP();
        int signal = WiFi.RSSI();
        int clientConnected = tcpClient.connected();
        Serial.printf(
                "WiFi.ready(): %d\t\t"
                "IP: %d.%d.%d.%d\t\t"
                "RSSI: %d\t\t"
                "TCP client connected: %d\t\t"
                "millis(): %" PRIu32 "\n",
                wifiReady,
                ip[0],ip[1],ip[2],ip[3],
                signal,
                clientConnected,
                last_update);
    }

    if(timeSince(lastLedToggle) >= 200UL ) {
        lastLedToggle = millis();
        static bool ledOn = true;
        ledOn = !ledOn;
        digitalWrite(LED_PIN, ledOn);
    }
    Particle.process();
}
<|endoftext|>


<commit_before>#include "hid_manager.hpp"

namespace {
class control_led final : public pqrs::dispatcher::extra::dispatcher_client {
public:
  control_led(const control_led&) = delete;

  control_led(std::weak_ptr<pqrs::dispatcher::dispatcher> weak_dispatcher,
              bool led_state) : dispatcher_client(weak_dispatcher) {
    std::vector<std::pair<krbn::hid_usage_page, krbn::hid_usage>> targets({
        std::make_pair(krbn::hid_usage_page::generic_desktop, krbn::hid_usage::gd_keyboard),
    });

    hid_manager_ = std::make_unique<krbn::hid_manager>(weak_dispatcher,
                                                       targets);

    hid_manager_->device_detected.connect([led_state](auto&& weak_hid) {
      if (auto hid = weak_hid.lock()) {
        hid->opened.connect([led_state, weak_hid] {
          if (auto hid = weak_hid.lock()) {
            hid->async_set_caps_lock_led_state(led_state ? krbn::led_state::on : krbn::led_state::off);
            krbn::logger::get_logger().info("async_set_caps_lock_led_state is called.");
          }
        });

        hid->open_failed.connect([weak_hid](auto&& error_code) {
          if (auto hid = weak_hid.lock()) {
            krbn::logger::get_logger().error("failed to open {0}", hid->get_name_for_log());
          }
        });

        hid->async_open();
      }
    });

    hid_manager_->async_start();
  }

  ~control_led(void) {
    hid_manager_ = nullptr;
  }

private:
  std::unique_ptr<krbn::hid_manager> hid_manager_;
};
} // namespace

int main(int argc, const char* argv[]) {
  krbn::thread_utility::register_main_thread();

  signal(SIGINT, [](int) {
    CFRunLoopStop(CFRunLoopGetMain());
  });

  if (getuid() != 0) {
    krbn::logger::get_logger().error("control_led requires root privilege.");
    return 1;
  }

  if (argc == 1) {
    krbn::logger::get_logger().error("Usage: control_led on|off");
    krbn::logger::get_logger().error("  Example: control_led on");
    krbn::logger::get_logger().error("  Example: control_led off");
    return 1;
  }

  auto time_source = std::make_shared<pqrs::dispatcher::hardware_time_source>();
  auto dispatcher = std::make_shared<pqrs::dispatcher::dispatcher>(time_source);

  auto p = std::make_unique<control_led>(dispatcher,
                                         std::string(argv[1]) == "on");

  CFRunLoopRun();

  p = nullptr;

  return 0;
}
<commit_msg>update appendix/control_led<commit_after>#include "hid_manager.hpp"

namespace {
class control_led final : public pqrs::dispatcher::extra::dispatcher_client {
public:
  control_led(const control_led&) = delete;

  control_led(std::weak_ptr<pqrs::dispatcher::dispatcher> weak_dispatcher,
              bool led_state) : dispatcher_client(weak_dispatcher) {
    std::vector<std::pair<krbn::hid_usage_page, krbn::hid_usage>> targets({
        std::make_pair(krbn::hid_usage_page::generic_desktop, krbn::hid_usage::gd_keyboard),
    });

    hid_manager_ = std::make_unique<krbn::hid_manager>(weak_dispatcher,
                                                       targets);

    hid_manager_->device_detected.connect([led_state](auto&& weak_hid) {
      if (auto hid = weak_hid.lock()) {
        krbn::logger::get_logger().info("{0} is detected.", hid->get_name_for_log());

        hid->opened.connect([led_state, weak_hid] {
          if (auto hid = weak_hid.lock()) {
            hid->async_set_caps_lock_led_state(led_state ? krbn::led_state::on : krbn::led_state::off);
            krbn::logger::get_logger().info("async_set_caps_lock_led_state is called.");
          }
        });

        hid->open_failed.connect([weak_hid](auto&& error_code) {
          if (auto hid = weak_hid.lock()) {
            krbn::logger::get_logger().error("failed to open {0}", hid->get_name_for_log());
          }
        });

        hid->async_open();
      }
    });

    hid_manager_->async_start();
  }

  ~control_led(void) {
    hid_manager_ = nullptr;
  }

private:
  std::unique_ptr<krbn::hid_manager> hid_manager_;
};
} // namespace

int main(int argc, const char* argv[]) {
  krbn::thread_utility::register_main_thread();

  signal(SIGINT, [](int) {
    CFRunLoopStop(CFRunLoopGetMain());
  });

  if (getuid() != 0) {
    krbn::logger::get_logger().error("control_led requires root privilege.");
    return 1;
  }

  if (argc == 1) {
    krbn::logger::get_logger().error("Usage: control_led on|off");
    krbn::logger::get_logger().error("  Example: control_led on");
    krbn::logger::get_logger().error("  Example: control_led off");
    return 1;
  }

  auto time_source = std::make_shared<pqrs::dispatcher::hardware_time_source>();
  auto dispatcher = std::make_shared<pqrs::dispatcher::dispatcher>(time_source);

  auto p = std::make_unique<control_led>(dispatcher,
                                         std::string(argv[1]) == "on");

  CFRunLoopRun();

  p = nullptr;

  return 0;
}
<|endoftext|>