<commit_before>/*
 * REKSolver.cpp
 *
 *  Created on: May 4, 2015
 *      Author: zouzias
 */

#include "REKSolver.hpp"

#include "../vector/DenseVector.hpp"
#include "../samplers/AliasSampler.hpp"

DoubleVector*	 REKSolver::solve(const DoubleMatrix& A, const DoubleVector& b, double MaxSeconds){
	DoubleVector* vector = new DenseVector();

	return vector;
};

DoubleVector* REKSolver::solve(const DoubleMatrix& A, const DoubleVector& b, long MaxIterations){

	double val;
  int i_k, j_k;
  DoubleVector* x = new DenseVector(A.getColumnDimension());
  DoubleVector* z = new DenseVector(b);
  DoubleVector* rowNorms = A.rowNorms();
	DoubleVector* columnNorms = A.columnNorms();

  AliasSampler rowSampler(*rowNorms);
	AliasSampler colSampler(*columnNorms);

  for (int k = 0; k < MaxIterations; k++) {
  	i_k = rowSampler.walkerSample();
  	j_k = colSampler.walkerSample();

    val = -z->DDOT(A.getColumn(j_k)) / columnNorms->get(j_k);     // val = - dot(z, A(:, j_k)) / colProbs(j_k)
    z->DAXPY(val, A.getColumn(j_k));                             // z = z + val * A(:, j_k);

    val = x->DDOT(A.getRow(i_k));                                // val = dot(x, A(i_k, :))
    val = (b.get(i_k) - z->get(i_k) - val) / rowNorms->get(i_k);  // val = (b(i_k) - z(i_k) - val) / roProbs(i_k)
    x->DAXPY(val, A.getRow(i_k));                                // x = x + val * A(i_k, :);
  }

	delete z;
	delete rowNorms;
	delete columnNorms;

  return x;
};
<commit_msg>Moved back to extended Kaczmarz<commit_after>/*
 * REKSolver.cpp
 *
 *  Created on: May 4, 2015
 *      Author: zouzias
 */

#include "REKSolver.hpp"

#include "../vector/DenseVector.hpp"
#include "../samplers/AliasSampler.hpp"
#include <stdlib.h>

DoubleVector*	 REKSolver::solve(const DoubleMatrix& A, const DoubleVector& b, double MaxSeconds){
	DoubleVector* vector = new DenseVector();

	return vector;
};

DoubleVector* REKSolver::solve(const DoubleMatrix& A, const DoubleVector& b, long MaxIterations){

	double val;
  int i_k, j_k;
  DoubleVector* x = new DenseVector(A.getColumnDimension());
  DoubleVector* z = new DenseVector(b);
  DoubleVector* rowNorms = A.rowNorms();
	DoubleVector* columnNorms = A.columnNorms();

  AliasSampler rowSampler(*rowNorms);
	AliasSampler colSampler(*columnNorms);

	// Initialize Alias samplers, O(n)
	rowSampler.initSampler();
	colSampler.initSampler();

  for (int k = 0; k < MaxIterations; k++) {
  	//i_k = rowSampler.walkerSample();
  	//j_k = colSampler.walkerSample();

		// Extended Kaczmarz
		i_k = k % A.getRowDimension();
		j_k = k % A.getColumnDimension();

    val = -z->DDOT(A.getColumn(j_k)) / columnNorms->get(j_k);     // val = - dot(z, A(:, j_k)) / colProbs(j_k)
    z->DAXPY(val, A.getColumn(j_k));                             // z = z + val * A(:, j_k);

    val = x->DDOT(A.getRow(i_k));                                // val = dot(x, A(i_k, :))
    val = (b.get(i_k) - z->get(i_k) - val) / rowNorms->get(i_k);  // val = (b(i_k) - z(i_k) - val) / roProbs(i_k)
    x->DAXPY(val, A.getRow(i_k));                                // x = x + val * A(i_k, :);
  }

	delete z;
	delete rowNorms;
	delete columnNorms;

  return x;
};
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * 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.
 *
 * 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.
 *
 * \file TractionCvSpace.hxx
 *
 * A memory config protocol compatible Memory Space for reading and writing CVs
 * of DCC locomotives.
 *
 * @author Balazs Racz
 * @date 16 May 2015
 */

#include "openlcb/TractionCvSpace.hxx"
#include "openlcb/TractionDefs.hxx"

// We try this many times to write a CV using railcom if we keep getting an
// unknown railcom response. After that we try to verify with a read.
static const int WRITE_RETRY_COUNT_ON_UNKNOWN = 10;
// We try at most this many times to read a CV if we keep getting an unknown
// railcom response. After that we report an error.
static const int READ_RETRY_COUNT_ON_UNKNOWN = 10;

// Maximum time we keep trying to read or write a given CV.
static const int RAILCOM_POM_OP_TIMEOUT_MSEC = 2000;

namespace openlcb
{

TractionCvSpace::TractionCvSpace(MemoryConfigHandler *parent,
                                 dcc::PacketFlowInterface *track,
                                 dcc::RailcomHubFlow *railcom_hub,
                                 uint8_t space_id)
    : StateFlowBase(parent->service())
    , parent_(parent)
    , track_(track)
    , railcomHub_(railcom_hub)
    , errorCode_(ERROR_NOOP)
    , spaceId_(space_id)
    , timer_(this)
{
    parent_->registry()->insert(nullptr, spaceId_, this);
    // We purposefully do not start the state flow until a request comes in.
}

TractionCvSpace::~TractionCvSpace()
{
    parent_->registry()->erase(nullptr, spaceId_, this);
    if (errorCode_ == ERROR_PENDING)
    {
        timer_.cancel();
    }
}

bool TractionCvSpace::set_node(Node *node)
{
    if (!node)
    {
        return false;
    }
    NodeID id = node->node_id();
    /* NOTE(balazs.racz): It is difficult to figure out the DCC address given
     * an abstract NMRAnet node. Here we hardcode the reserved DCC node ID
     * space, which is not a great solution. */
    if ((id & 0xFFFF00000000ULL) == TractionDefs::NODE_ID_DCC)
    {
        uint16_t new_address = id & 0xFFFFU;
        if (dccAddress_ != new_address)
        {
            dccAddress_ = new_address;
            errorCode_ = ERROR_NOOP;
        }
        return true;
    }
    else
    {
        return false;
    }
}

const unsigned TractionCvSpace::MAX_CV;

size_t TractionCvSpace::read(address_t source, uint8_t *dst, size_t len,
                             errorcode_t *error, Notifiable *again)
{
    if (source == OFFSET_CV_INDEX) {
        lastIndexedNode_ = dccAddress_;
        uint8_t* lastcv = (uint8_t*)&lastIndexedCv_;
        if (len > 0) dst[0] = lastcv[3];
        if (len > 1) dst[1] = lastcv[2];
        if (len > 2) dst[2] = lastcv[1];
        if (len > 3) dst[3] = lastcv[0];
        return std::min(len, size_t(4));
    }
    if (source == OFFSET_CV_VALUE) {
        if (dccAddress_ != lastIndexedNode_) {
            *error = Defs::ERROR_PERMANENT;
            return 0;
        }
        // Translate from user-visible CV to wire protocol CV.
        source = lastIndexedCv_ - 1;
        // fall through to regular processing
    }
    LOG(INFO, "cv read %" PRId32, source);
    if (source > MAX_CV)
    {
        *error = MemoryConfigDefs::ERROR_OUT_OF_BOUNDS;
        errorCode_ = ERROR_NOOP;
        return 0;
    }
    if (source == cvNumber_) {
        if (errorCode_ == ERROR_OK) {
            *dst = cvData_;
            errorCode_ = ERROR_NOOP;
            return 1;
        } else if (errorCode_ == _ERROR_TIMEOUT) {
            *error = Defs::ERROR_OPENLCB_TIMEOUT;
            errorCode_ = ERROR_NOOP;
            return 0;
        }
    }
    done_ = again;
    cvNumber_ = source;
    errorCode_ = ERROR_NOOP;
    cvData_ = 0;
    numTry_ = 0;
    start_flow(STATE(try_read1));
    *error = ERROR_AGAIN;
    deadline_ = os_get_time_monotonic() + MSEC_TO_NSEC(RAILCOM_POM_OP_TIMEOUT_MSEC);
    return 0;
}

StateFlowBase::Action TractionCvSpace::try_read1()
{
    return allocate_and_call(track_, STATE(fill_read1_packet));
}
StateFlowBase::Action TractionCvSpace::try_write1()
{
    return allocate_and_call(track_, STATE(fill_write1_packet));
}

StateFlowBase::Action TractionCvSpace::fill_read1_packet()
{
    auto *b = get_allocation_result(track_);
    b->data()->start_dcc_packet();
    /** @TODO(balazs.racz) here we make bad assumptions about how to decide
     * between long and short addresses */
    if (dccAddress_ >= 0x80)
    {
        b->data()->add_dcc_address(dcc::DccLongAddress(dccAddress_));
    }
    else
    {
        b->data()->add_dcc_address(dcc::DccShortAddress(dccAddress_));
    }
    b->data()->add_dcc_pom_read1(cvNumber_);
    b->data()->feedback_key = reinterpret_cast<uintptr_t>(this);
    railcomHub_->register_port(this);
    errorCode_ = ERROR_PENDING;
    track_->send(b);
    return sleep_and_call(&timer_, MSEC_TO_NSEC(500), STATE(read_returned));
}

StateFlowBase::Action TractionCvSpace::read_returned()
{
    LOG(WARNING, "railcom read returned status %d value %d", errorCode_, cvData_);
    switch (errorCode_) {
    case ERROR_PENDING:
        errorCode_ = _ERROR_TIMEOUT;
        railcomHub_->unregister_port(this);
        break;
    case ERROR_OK:
        break;
    default:
    case ERROR_UNKNOWN_RESPONSE:
        if (numTry_ >= READ_RETRY_COUNT_ON_UNKNOWN) {
            errorCode_ = _ERROR_TIMEOUT;
            break;
        }
        numTry_++;
        return call_immediately(STATE(try_read1));
    case _ERROR_BUSY:
        if (os_get_time_monotonic() > deadline_) {
            errorCode_ = _ERROR_TIMEOUT;
            break;
        }
        return call_immediately(STATE(try_read1));
    }
    done_->notify();
    return exit();
}

size_t TractionCvSpace::write(address_t destination, const uint8_t *src,
                              size_t len, errorcode_t *error, Notifiable *again)
{
    if (destination == OFFSET_CV_INDEX) {
        lastIndexedNode_ = dccAddress_;
        uint8_t* lastcv = (uint8_t*)&lastIndexedCv_;
        if (len > 0) lastcv[3] = src[0];
        if (len > 1) lastcv[2] = src[1];
        if (len > 2) lastcv[1] = src[2];
        if (len > 3) lastcv[0] = src[3];
        return std::min(len, size_t(4));
    }
    if (destination == OFFSET_CV_VALUE) {
        if (dccAddress_ != lastIndexedNode_) {
            *error = Defs::ERROR_TEMPORARY;
            return 0;
        }
        // Translate from user-visible CV to wire protocol CV.
        destination = lastIndexedCv_ - 1;
        // fall through to regular processing
    }
    LOG(INFO, "cv write %" PRIu32 " := %d", destination, *src);
    if (destination > MAX_CV)
    {
        *error = MemoryConfigDefs::ERROR_OUT_OF_BOUNDS;
        errorCode_ = ERROR_NOOP;
        return 0;
    }
    if (errorCode_ == ERROR_OK && destination == cvNumber_)
    {
        errorCode_ = ERROR_NOOP;
        return 1;
    }
    if (errorCode_ == _ERROR_TIMEOUT && destination == cvNumber_)
    {
        *error = Defs::ERROR_TEMPORARY | 1;
        errorCode_ = ERROR_NOOP;
        return 0;
    }
    done_ = again;
    cvNumber_ = destination;
    cvData_ = *src;
    numTry_ = 0;
    errorCode_ = ERROR_NOOP;
    start_flow(STATE(try_write1));
    *error = ERROR_AGAIN;
    deadline_ = os_get_time_monotonic() + MSEC_TO_NSEC(RAILCOM_POM_OP_TIMEOUT_MSEC);
    return 0;
}

StateFlowBase::Action TractionCvSpace::fill_write1_packet()
{
    auto *b = get_allocation_result(track_);
    b->data()->start_dcc_packet();
    // POM write packets need to appear at least twice on non-back-to-back
    // packets by the standard. We make 4 back to back packets and that
    // fulfills the requirement.
    b->data()->packet_header.rept_count = 3;
    /** @TODO(balazs.racz) here we make bad assumptions about how to decide
     * between long and short addresses */
    if (dccAddress_ >= 0x80)
    {
        b->data()->add_dcc_address(dcc::DccLongAddress(dccAddress_));
    }
    else
    {
        b->data()->add_dcc_address(dcc::DccShortAddress(dccAddress_));
    }
    b->data()->add_dcc_pom_write1(cvNumber_, cvData_);
    b->data()->feedback_key = reinterpret_cast<uintptr_t>(this);
    railcomHub_->register_port(this);
    errorCode_ = ERROR_PENDING;
    track_->send(b);
    return sleep_and_call(&timer_, MSEC_TO_NSEC(500), STATE(write_returned));
}

StateFlowBase::Action TractionCvSpace::write_returned()
{
    LOG(WARNING, "railcom write returned status %d value %d", errorCode_, cvData_);
    switch (errorCode_) {
    case ERROR_PENDING:
        errorCode_ = _ERROR_TIMEOUT;
        railcomHub_->unregister_port(this);
        break;
    case ERROR_OK:
        break;
    default:
    case ERROR_UNKNOWN_RESPONSE:
        if (numTry_ >= WRITE_RETRY_COUNT_ON_UNKNOWN) {
            // We switch from writing to reading if we had tried many enough
            // times. Maybe the write was actually successful.
            return call_immediately(STATE(try_read1));
        }
        numTry_++;
        return call_immediately(STATE(try_write1));
    case _ERROR_BUSY:
        if (os_get_time_monotonic() > deadline_) {
            errorCode_ = _ERROR_TIMEOUT;
            break;
        }
        /// @TODO(balazs.racz) keep a timestamp to not keep trying forever.
        return call_immediately(STATE(try_write1));
    }
    done_->notify();
    return exit();
}

void TractionCvSpace::record_railcom_status(unsigned code)
{
    errorCode_ = code;
    timer_.trigger();
    railcomHub_->unregister_port(this);
}

void TractionCvSpace::send(Buffer<dcc::RailcomHubData> *b, unsigned priority)
{
    AutoReleaseBuffer<dcc::RailcomHubData> ar(b);
    if (errorCode_ != ERROR_PENDING)
        return;
    const dcc::Feedback &f = *b->data();
    if (f.feedbackKey != (reinterpret_cast<uintptr_t>(this)) || f.channel == 0xff)
    {
        // Skip railcom from other packets; also skip the railcom-based
        // occupancy information packets.
        return;
    }
    LOG(INFO, "CV railcom feedback ch=%d: %s", f.channel, railcom_debug(f).c_str());
    if (!f.ch2Size)
    {
        return record_railcom_status(ERROR_NO_RAILCOM_CH2_DATA);
    }
    dcc::parse_railcom_data(f, &interpretedResponse_);
    unsigned new_status = ERROR_PENDING;
    for (const auto& e : interpretedResponse_) {
        if (e.railcom_channel != 2) continue;
        switch(e.type) {
        case dcc::RailcomPacket::BUSY:
            if (new_status == ERROR_PENDING) {
                new_status = _ERROR_BUSY;
            }
            break;
        case dcc::RailcomPacket::NACK:
            if (new_status == ERROR_PENDING) {
                new_status = ERROR_NACK;
            }
            break;
        case dcc::RailcomPacket::ACK:
            if (new_status == ERROR_PENDING) {
                new_status = ERROR_OK;
            }
            break;
        case dcc::RailcomPacket::GARBAGE:
            if (new_status == ERROR_PENDING) {
                new_status = ERROR_GARBAGE;
            }
            break;
        case dcc::RailcomPacket::MOB_POM:
            cvData_ = e.argument;
            new_status = ERROR_OK;
            break;
        default:
            if (new_status == ERROR_PENDING) {
                new_status = ERROR_UNKNOWN_RESPONSE;
            }
            break;
        }
    }
    return record_railcom_status(new_status);
}

} // namespace openlcb
<commit_msg>Minor fixes to tractioncvspace: - repeat count for POM write packet was not effective. - ignores NACK response from the decoder. These were abused by other decoders as ACK in an earlier verion of the standard.<commit_after>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * 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.
 *
 * 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.
 *
 * \file TractionCvSpace.hxx
 *
 * A memory config protocol compatible Memory Space for reading and writing CVs
 * of DCC locomotives.
 *
 * @author Balazs Racz
 * @date 16 May 2015
 */

#include "openlcb/TractionCvSpace.hxx"
#include "openlcb/TractionDefs.hxx"

// We try this many times to write a CV using railcom if we keep getting an
// unknown railcom response. After that we try to verify with a read.
static const int WRITE_RETRY_COUNT_ON_UNKNOWN = 10;
// We try at most this many times to read a CV if we keep getting an unknown
// railcom response. After that we report an error.
static const int READ_RETRY_COUNT_ON_UNKNOWN = 10;

// Maximum time we keep trying to read or write a given CV.
static const int RAILCOM_POM_OP_TIMEOUT_MSEC = 2000;

namespace openlcb
{

TractionCvSpace::TractionCvSpace(MemoryConfigHandler *parent,
                                 dcc::PacketFlowInterface *track,
                                 dcc::RailcomHubFlow *railcom_hub,
                                 uint8_t space_id)
    : StateFlowBase(parent->service())
    , parent_(parent)
    , track_(track)
    , railcomHub_(railcom_hub)
    , errorCode_(ERROR_NOOP)
    , spaceId_(space_id)
    , timer_(this)
{
    parent_->registry()->insert(nullptr, spaceId_, this);
    // We purposefully do not start the state flow until a request comes in.
}

TractionCvSpace::~TractionCvSpace()
{
    parent_->registry()->erase(nullptr, spaceId_, this);
    if (errorCode_ == ERROR_PENDING)
    {
        timer_.cancel();
    }
}

bool TractionCvSpace::set_node(Node *node)
{
    if (!node)
    {
        return false;
    }
    NodeID id = node->node_id();
    /* NOTE(balazs.racz): It is difficult to figure out the DCC address given
     * an abstract NMRAnet node. Here we hardcode the reserved DCC node ID
     * space, which is not a great solution. */
    if ((id & 0xFFFF00000000ULL) == TractionDefs::NODE_ID_DCC)
    {
        uint16_t new_address = id & 0xFFFFU;
        if (dccAddress_ != new_address)
        {
            dccAddress_ = new_address;
            errorCode_ = ERROR_NOOP;
        }
        return true;
    }
    else
    {
        return false;
    }
}

const unsigned TractionCvSpace::MAX_CV;

size_t TractionCvSpace::read(address_t source, uint8_t *dst, size_t len,
                             errorcode_t *error, Notifiable *again)
{
    if (source == OFFSET_CV_INDEX) {
        lastIndexedNode_ = dccAddress_;
        uint8_t* lastcv = (uint8_t*)&lastIndexedCv_;
        if (len > 0) dst[0] = lastcv[3];
        if (len > 1) dst[1] = lastcv[2];
        if (len > 2) dst[2] = lastcv[1];
        if (len > 3) dst[3] = lastcv[0];
        return std::min(len, size_t(4));
    }
    if (source == OFFSET_CV_VALUE) {
        if (dccAddress_ != lastIndexedNode_) {
            *error = Defs::ERROR_PERMANENT;
            return 0;
        }
        // Translate from user-visible CV to wire protocol CV.
        source = lastIndexedCv_ - 1;
        // fall through to regular processing
    }
    LOG(INFO, "cv read %" PRId32, source);
    if (source > MAX_CV)
    {
        *error = MemoryConfigDefs::ERROR_OUT_OF_BOUNDS;
        errorCode_ = ERROR_NOOP;
        return 0;
    }
    if (source == cvNumber_) {
        if (errorCode_ == ERROR_OK) {
            *dst = cvData_;
            errorCode_ = ERROR_NOOP;
            return 1;
        } else if (errorCode_ == _ERROR_TIMEOUT) {
            *error = Defs::ERROR_OPENLCB_TIMEOUT;
            errorCode_ = ERROR_NOOP;
            return 0;
        }
    }
    done_ = again;
    cvNumber_ = source;
    errorCode_ = ERROR_NOOP;
    cvData_ = 0;
    numTry_ = 0;
    start_flow(STATE(try_read1));
    *error = ERROR_AGAIN;
    deadline_ = os_get_time_monotonic() + MSEC_TO_NSEC(RAILCOM_POM_OP_TIMEOUT_MSEC);
    return 0;
}

StateFlowBase::Action TractionCvSpace::try_read1()
{
    return allocate_and_call(track_, STATE(fill_read1_packet));
}
StateFlowBase::Action TractionCvSpace::try_write1()
{
    return allocate_and_call(track_, STATE(fill_write1_packet));
}

StateFlowBase::Action TractionCvSpace::fill_read1_packet()
{
    auto *b = get_allocation_result(track_);
    b->data()->start_dcc_packet();
    /** @TODO(balazs.racz) here we make bad assumptions about how to decide
     * between long and short addresses */
    if (dccAddress_ >= 0x80)
    {
        b->data()->add_dcc_address(dcc::DccLongAddress(dccAddress_));
    }
    else
    {
        b->data()->add_dcc_address(dcc::DccShortAddress(dccAddress_));
    }
    b->data()->add_dcc_pom_read1(cvNumber_);
    b->data()->feedback_key = reinterpret_cast<uintptr_t>(this);
    railcomHub_->register_port(this);
    errorCode_ = ERROR_PENDING;
    track_->send(b);
    return sleep_and_call(&timer_, MSEC_TO_NSEC(500), STATE(read_returned));
}

StateFlowBase::Action TractionCvSpace::read_returned()
{
    LOG(WARNING, "railcom read returned status %d value %d", errorCode_, cvData_);
    switch (errorCode_) {
    case ERROR_PENDING:
        errorCode_ = _ERROR_TIMEOUT;
        railcomHub_->unregister_port(this);
        break;
    case ERROR_OK:
        break;
    default:
    case ERROR_UNKNOWN_RESPONSE:
        if (numTry_ >= READ_RETRY_COUNT_ON_UNKNOWN) {
            errorCode_ = _ERROR_TIMEOUT;
            break;
        }
        numTry_++;
        return call_immediately(STATE(try_read1));
    case _ERROR_BUSY:
        if (os_get_time_monotonic() > deadline_) {
            errorCode_ = _ERROR_TIMEOUT;
            break;
        }
        return call_immediately(STATE(try_read1));
    }
    done_->notify();
    return exit();
}

size_t TractionCvSpace::write(address_t destination, const uint8_t *src,
                              size_t len, errorcode_t *error, Notifiable *again)
{
    if (destination == OFFSET_CV_INDEX) {
        lastIndexedNode_ = dccAddress_;
        uint8_t* lastcv = (uint8_t*)&lastIndexedCv_;
        if (len > 0) lastcv[3] = src[0];
        if (len > 1) lastcv[2] = src[1];
        if (len > 2) lastcv[1] = src[2];
        if (len > 3) lastcv[0] = src[3];
        return std::min(len, size_t(4));
    }
    if (destination == OFFSET_CV_VALUE) {
        if (dccAddress_ != lastIndexedNode_) {
            *error = Defs::ERROR_TEMPORARY;
            return 0;
        }
        // Translate from user-visible CV to wire protocol CV.
        destination = lastIndexedCv_ - 1;
        // fall through to regular processing
    }
    LOG(INFO, "cv write %" PRIu32 " := %d", destination, *src);
    if (destination > MAX_CV)
    {
        *error = MemoryConfigDefs::ERROR_OUT_OF_BOUNDS;
        errorCode_ = ERROR_NOOP;
        return 0;
    }
    if (errorCode_ == ERROR_OK && destination == cvNumber_)
    {
        errorCode_ = ERROR_NOOP;
        return 1;
    }
    if (errorCode_ == _ERROR_TIMEOUT && destination == cvNumber_)
    {
        *error = Defs::ERROR_TEMPORARY | 1;
        errorCode_ = ERROR_NOOP;
        return 0;
    }
    done_ = again;
    cvNumber_ = destination;
    cvData_ = *src;
    numTry_ = 0;
    errorCode_ = ERROR_NOOP;
    start_flow(STATE(try_write1));
    *error = ERROR_AGAIN;
    deadline_ = os_get_time_monotonic() + MSEC_TO_NSEC(RAILCOM_POM_OP_TIMEOUT_MSEC);
    return 0;
}

StateFlowBase::Action TractionCvSpace::fill_write1_packet()
{
    auto *b = get_allocation_result(track_);
    b->data()->start_dcc_packet();
    /** @TODO(balazs.racz) here we make bad assumptions about how to decide
     * between long and short addresses */
    if (dccAddress_ >= 0x80)
    {
        b->data()->add_dcc_address(dcc::DccLongAddress(dccAddress_));
    }
    else
    {
        b->data()->add_dcc_address(dcc::DccShortAddress(dccAddress_));
    }
    b->data()->add_dcc_pom_write1(cvNumber_, cvData_);
    b->data()->feedback_key = reinterpret_cast<uintptr_t>(this);
    // POM write packets need to appear at least twice on non-back-to-back
    // packets by the standard. We make 4 back to back packets and that
    // fulfills the requirement.
    b->data()->packet_header.rept_count = 3;
    railcomHub_->register_port(this);
    errorCode_ = ERROR_PENDING;
    track_->send(b);
    return sleep_and_call(&timer_, MSEC_TO_NSEC(500), STATE(write_returned));
}

StateFlowBase::Action TractionCvSpace::write_returned()
{
    LOG(WARNING, "railcom write returned status %d value %d", errorCode_, cvData_);
    switch (errorCode_) {
    case ERROR_PENDING:
        errorCode_ = _ERROR_TIMEOUT;
        railcomHub_->unregister_port(this);
        break;
    case ERROR_OK:
        break;
    default:
    case ERROR_UNKNOWN_RESPONSE:
        if (numTry_ >= WRITE_RETRY_COUNT_ON_UNKNOWN) {
            // We switch from writing to reading if we had tried many enough
            // times. Maybe the write was actually successful.
            return call_immediately(STATE(try_read1));
        }
        numTry_++;
        return call_immediately(STATE(try_write1));
    case _ERROR_BUSY:
        if (os_get_time_monotonic() > deadline_) {
            errorCode_ = _ERROR_TIMEOUT;
            break;
        }
        /// @TODO(balazs.racz) keep a timestamp to not keep trying forever.
        return call_immediately(STATE(try_write1));
    }
    done_->notify();
    return exit();
}

void TractionCvSpace::record_railcom_status(unsigned code)
{
    errorCode_ = code;
    timer_.trigger();
    railcomHub_->unregister_port(this);
}

void TractionCvSpace::send(Buffer<dcc::RailcomHubData> *b, unsigned priority)
{
    AutoReleaseBuffer<dcc::RailcomHubData> ar(b);
    if (errorCode_ != ERROR_PENDING)
        return;
    const dcc::Feedback &f = *b->data();
    if (f.feedbackKey != (reinterpret_cast<uintptr_t>(this)) || f.channel == 0xff)
    {
        // Skip railcom from other packets; also skip the railcom-based
        // occupancy information packets.
        return;
    }
    LOG(INFO, "CV railcom feedback ch=%d: %s", f.channel, railcom_debug(f).c_str());
    if (!f.ch2Size)
    {
        return record_railcom_status(ERROR_NO_RAILCOM_CH2_DATA);
    }
    dcc::parse_railcom_data(f, &interpretedResponse_);
    unsigned new_status = ERROR_PENDING;
    for (const auto& e : interpretedResponse_) {
        if (e.railcom_channel != 2) continue;
        switch(e.type) {
        case dcc::RailcomPacket::BUSY:
            if (new_status == ERROR_PENDING) {
                new_status = _ERROR_BUSY;
            }
            break;
        case dcc::RailcomPacket::NACK:
            if (new_status == ERROR_PENDING) {
                // We ignore NACK responses because certain versions ofthe
                // standard had NACK interpreted the same way as ACK as well as
                // it was being used as a filler. There are locomotives out
                // there who do this.
                // new_status = ERROR_NACK;
            }
            break;
        case dcc::RailcomPacket::ACK:
            if (new_status == ERROR_PENDING) {
                new_status = ERROR_OK;
            }
            break;
        case dcc::RailcomPacket::GARBAGE:
            if (new_status == ERROR_PENDING) {
                new_status = ERROR_GARBAGE;
            }
            break;
        case dcc::RailcomPacket::MOB_POM:
            cvData_ = e.argument;
            new_status = ERROR_OK;
            break;
        default:
            if (new_status == ERROR_PENDING) {
                new_status = ERROR_UNKNOWN_RESPONSE;
            }
            break;
        }
    }
    return record_railcom_status(new_status);
}

} // namespace openlcb
<|endoftext|>


<commit_before>#include <BALL/FORMAT/molFileFactory.h>

#include <BALL/FORMAT/genericMolFile.h>
#include <BALL/FORMAT/antechamberFile.h>
#include <BALL/FORMAT/PDBFile.h>
#include <BALL/FORMAT/HINFile.h>
#include <BALL/FORMAT/MOLFile.h>
#include <BALL/FORMAT/MOL2File.h>
#include <BALL/FORMAT/SDFile.h>
#include <BALL/FORMAT/XYZFile.h>
#include <BALL/FORMAT/dockResultFile.h>

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>

#include <BALL/DATATYPE/string.h>

namespace BALL
{

	GenericMolFile* MolFileFactory::open(const String& name, File::OpenMode open_mode)
	{
		bool compression = false;
		String filename = name;

		if (name.hasSuffix(".gz"))
		{
			compression = true;
		}
		else if (open_mode == std::ios::in && !isFileExtensionSupported(filename)) // check whether file is zipped
		{
			std::ifstream zipped_file(filename.c_str(), std::ios_base::in | std::ios_base::binary);
			boost::iostreams::filtering_istream in;
			in.push(boost::iostreams::gzip_decompressor());
			in.push(zipped_file);
			bool ok = false;
			try
			{
				string s;
				ok = std::getline(in,s);
			}
			catch (const boost::iostreams::gzip_error& e)
			{
				compression = false;
			}
			if (ok) compression = true;
		}

		if (compression)
		{
			compression = true;
			String unzipped_filename;
			if (name.hasSuffix(".gz"))
			{
				String tmp = name.before(".gz");
				String ext = tmp.substr(tmp.find_last_of("."));
				File::createTemporaryFilename(unzipped_filename, ext);
			}
			else // unknown extension
			{
				File::createTemporaryFilename(unzipped_filename);
			}

			if (open_mode == std::ios::in)
			{
				std::ifstream zipped_file(name.c_str(), std::ios_base::in | std::ios_base::binary);
				boost::iostreams::filtering_istream in;
				in.push(boost::iostreams::gzip_decompressor());
				in.push(zipped_file);
				std::ofstream unzipped_file(unzipped_filename.c_str());
				boost::iostreams::copy(in, unzipped_file);
			}

			filename = unzipped_filename;
		}

		GenericMolFile* gmf = 0;
		if (filename.hasSuffix(".ac"))
		{
			gmf = new AntechamberFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".pdb") || filename.hasSuffix(".ent") || filename.hasSuffix(".brk"))
		{
			gmf = new PDBFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".hin"))
		{
			gmf = new HINFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".mol"))
		{
			gmf = new MOLFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".sdf"))
		{
			gmf = new SDFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".mol2"))
		{
			gmf = new MOL2File(filename, open_mode);
		}
		else if(filename.hasSuffix(".xyz"))
		{
			gmf = new XYZFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".drf"))
		{
			gmf = new DockResultFile(filename, open_mode);
		}
		else
		{
			if (open_mode == std::ios::in)
			{
				gmf = detectFormat(filename);
				// Make sure that temporary input-file is deleted when GenericMolFile is closed.
				if (gmf && compression)
				{
					gmf->defineInputAsTemporary();
				}
				return gmf;
			}
			return NULL;
		}

		if (compression)
		{
			if (open_mode == std::ios::in)
			{
				// Make sure that temporary input-file is deleted when GenericMolFile is closed.
				gmf->defineInputAsTemporary();
			}
			else
			{
				// Make sure that temporary output-file is compressed and then deleted when GenericMolFile is closed.
				gmf->enableOutputCompression(name);
			}
		}

		return gmf;
	}

	bool MolFileFactory::isFileExtensionSupported(String filename)
	{
		vector<String> exts;
		String s = getSupportedFormats();
		s.split(exts,",");
		for (Size i=0; i<exts.size(); i++)
		{
			if (filename.hasSuffix(exts[i]))
			{
				return true;
			}
		}
		return false;
	}

	GenericMolFile* MolFileFactory::open(const String& name, File::OpenMode open_mode, String default_format)
	{
		GenericMolFile* file = open(name, open_mode);
		if (file)
		{
			return file;
		}

		if (open_mode == std::ios::out)
		{
			bool compression = false;
			String filename = name;
			String zipped_filename = "";
			if (default_format.hasSuffix(".gz"))
			{
				compression = true;
				zipped_filename = filename;
				default_format = default_format.before(".gz");
				String unzipped_filename;
				File::createTemporaryFilename(unzipped_filename, default_format);
				filename = unzipped_filename;
			}

			if (default_format == "ac")
			{
				file = new AntechamberFile(filename, open_mode);
			}
			else if(default_format == "pdb" || default_format == "ent" || default_format == "brk")
			{
				file = new PDBFile(filename, open_mode);
			}
			else if(default_format == "hin")
			{
				file = new HINFile(filename, open_mode);
			}
			else if(default_format == "mol")
			{
				file = new MOLFile(filename, open_mode);
			}
			else if(default_format == "sdf")
			{
				file = new SDFile(filename, open_mode);
			}
			else if(default_format == "mol2")
			{
				file = new MOL2File(filename, open_mode);
			}
			else if(default_format == "xyz")
			{
				file = new XYZFile(filename, open_mode);
			}
			else if(default_format == "drf")
			{
				file = new DockResultFile(filename, open_mode);
			}
			// Make sure that temporary output-file is compressed and then deleted when GenericMolFile is closed.
			if (compression)
			{
				file->enableOutputCompression(zipped_filename);
			}
		}
		return file;
	}

	GenericMolFile* MolFileFactory::open(const String& name, File::OpenMode open_mode, GenericMolFile* default_format_file)
	{
		GenericMolFile* file = open(name, open_mode);
		if (file)
		{
			return file;
		}

		if (open_mode == std::ios::out)
		{
			bool compression = false;
			String filename = name;
			String zipped_filename = "";
			if (default_format_file->isCompressedFile())
			{
				compression = true;
				zipped_filename = filename;
				String unzipped_filename;
				File::createTemporaryFilename(unzipped_filename);
				filename = unzipped_filename;
			}

			if (dynamic_cast<AntechamberFile*>(default_format_file))
			{
				file = new AntechamberFile(filename, open_mode);
			}
			else if(dynamic_cast<PDBFile*>(default_format_file))
			{
				file = new PDBFile(filename, open_mode);
			}
			else if(dynamic_cast<HINFile*>(default_format_file))
			{
				file = new HINFile(filename, open_mode);
			}
			else if(dynamic_cast<SDFile*>(default_format_file))
			{
				file = new SDFile(filename, open_mode);
			}
			else if(dynamic_cast<MOL2File*>(default_format_file))
			{
				file = new MOL2File(filename, open_mode);
			}
			else if(dynamic_cast<MOLFile*>(default_format_file))
			{
				file = new MOLFile(filename, open_mode);
			}
			else if(dynamic_cast<XYZFile*>(default_format_file))
			{
				file = new XYZFile(filename, open_mode);
			}
			else if(dynamic_cast<DockResultFile*>(default_format_file))
			{
				file = new DockResultFile(filename, open_mode);
			}
			// Make sure that temporary output-file is compressed and then deleted when GenericMolFile is closed.
			if (compression)
			{
				file->enableOutputCompression(zipped_filename);
			}
		}
		return file;
	}

	String MolFileFactory::getSupportedFormats()
	{
		String formats = "mol2,sdf,drf,pdb,ac,ent,brk,hin,mol,xyz,mol2.gz,sdf.gz,drf.gz,pdb.gz,ac.gz,ent.gz,brk.gz,hin.gz,mol.gz,xyz.gz";
		return formats;
	}

	GenericMolFile* MolFileFactory::detectFormat(const String& name)
	{
		LineBasedFile input(name, std::ios::in);
		bool empty_file = true;

		// Read at most 400 lines.
		// If no format-indicator is found, return NULL
		for (Size no=1; no < 400 && input.readLine(); no++)
		{
			String& line = input.getLine();
			if (!line.trim().empty())
			{
				empty_file = false;
			}
			if (line.hasPrefix("@<TRIPOS>MOLECULE"))
			{
				input.close();
				return new MOL2File(name, std::ios::in);
			}
			else if (line.hasPrefix("$$$$") || line.hasPrefix("M  END"))
			{
				input.close();
				return new SDFile(name, std::ios::in);
			}
			else if (line.hasPrefix("<dockingfile>"))
			{
				input.close();
				return new DockResultFile(name, std::ios::in);
			}
			else if (line.hasPrefix("HEADER") || line.hasPrefix("ATOM") || line.hasPrefix("USER"))
			{
				input.close();
				return new PDBFile(name, std::ios::in);
			}
		}

		if (empty_file)
		{
			Log.error() << std::endl << "[Error:] Specified input file is empty!" << std::endl << std::endl;
		}
		else
		{
			Log.error() << std::endl << "[Error:] Specified input file has unknown extension and its format could not be detected automatically!" << std::endl << std::endl;
		}
		return NULL;
	}
}

<commit_msg>MolFileFactory::open() Test for upper case file extensions.<commit_after>#include <BALL/FORMAT/molFileFactory.h>

#include <BALL/FORMAT/genericMolFile.h>
#include <BALL/FORMAT/antechamberFile.h>
#include <BALL/FORMAT/PDBFile.h>
#include <BALL/FORMAT/HINFile.h>
#include <BALL/FORMAT/MOLFile.h>
#include <BALL/FORMAT/MOL2File.h>
#include <BALL/FORMAT/SDFile.h>
#include <BALL/FORMAT/XYZFile.h>
#include <BALL/FORMAT/dockResultFile.h>

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>

#include <BALL/DATATYPE/string.h>

namespace BALL
{

	GenericMolFile* MolFileFactory::open(const String& name, File::OpenMode open_mode)
	{
		bool compression = false;
		String filename = name;

		if (name.hasSuffix(".gz"))
		{
			compression = true;
		}
		else if (open_mode == std::ios::in && !isFileExtensionSupported(filename)) // check whether file is zipped
		{
			std::ifstream zipped_file(filename.c_str(), std::ios_base::in | std::ios_base::binary);
			boost::iostreams::filtering_istream in;
			in.push(boost::iostreams::gzip_decompressor());
			in.push(zipped_file);
			bool ok = false;
			try
			{
				string s;
				ok = std::getline(in,s);
			}
			catch (const boost::iostreams::gzip_error& e)
			{
				compression = false;
			}
			if (ok) compression = true;
		}

		if (compression)
		{
			compression = true;
			String unzipped_filename;
			if (name.hasSuffix(".gz"))
			{
				String tmp = name.before(".gz");
				String ext = tmp.substr(tmp.find_last_of("."));
				File::createTemporaryFilename(unzipped_filename, ext);
			}
			else // unknown extension
			{
				File::createTemporaryFilename(unzipped_filename);
			}

			if (open_mode == std::ios::in)
			{
				std::ifstream zipped_file(name.c_str(), std::ios_base::in | std::ios_base::binary);
				boost::iostreams::filtering_istream in;
				in.push(boost::iostreams::gzip_decompressor());
				in.push(zipped_file);
				std::ofstream unzipped_file(unzipped_filename.c_str());
				boost::iostreams::copy(in, unzipped_file);
			}

			filename = unzipped_filename;
		}

		GenericMolFile* gmf = 0;
		if (filename.hasSuffix(".ac") || filename.hasSuffix(".AC"))
		{
			gmf = new AntechamberFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".pdb") || filename.hasSuffix(".ent") || filename.hasSuffix(".brk") ||
			filename.hasSuffix(".PDB") || filename.hasSuffix(".ENT") || filename.hasSuffix(".BRK"))
		{
			gmf = new PDBFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".hin") || filename.hasSuffix(".HIN"))
		{
			gmf = new HINFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".mol") || filename.hasSuffix(".MOL"))
		{
			gmf = new MOLFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".sdf") || filename.hasSuffix(".SDF"))
		{
			gmf = new SDFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".mol2") || filename.hasSuffix(".MOL2"))
		{
			gmf = new MOL2File(filename, open_mode);
		}
		else if(filename.hasSuffix(".xyz") || filename.hasSuffix(".XYZ"))
		{
			gmf = new XYZFile(filename, open_mode);
		}
		else if(filename.hasSuffix(".drf") || filename.hasSuffix(".DRF"))
		{
			gmf = new DockResultFile(filename, open_mode);
		}
		else
		{
			if (open_mode == std::ios::in)
			{
				gmf = detectFormat(filename);
				// Make sure that temporary input-file is deleted when GenericMolFile is closed.
				if (gmf && compression)
				{
					gmf->defineInputAsTemporary();
				}
				return gmf;
			}
			return NULL;
		}

		if (compression)
		{
			if (open_mode == std::ios::in)
			{
				// Make sure that temporary input-file is deleted when GenericMolFile is closed.
				gmf->defineInputAsTemporary();
			}
			else
			{
				// Make sure that temporary output-file is compressed and then deleted when GenericMolFile is closed.
				gmf->enableOutputCompression(name);
			}
		}

		return gmf;
	}

	bool MolFileFactory::isFileExtensionSupported(String filename)
	{
		vector<String> exts;
		String s = getSupportedFormats();
		s.split(exts,",");
		for (Size i=0; i<exts.size(); i++)
		{
			if (filename.hasSuffix(exts[i]))
			{
				return true;
			}
		}
		return false;
	}

	GenericMolFile* MolFileFactory::open(const String& name, File::OpenMode open_mode, String default_format)
	{
		GenericMolFile* file = open(name, open_mode);
		if (file)
		{
			return file;
		}

		if (open_mode == std::ios::out)
		{
			bool compression = false;
			String filename = name;
			String zipped_filename = "";
			if (default_format.hasSuffix(".gz"))
			{
				compression = true;
				zipped_filename = filename;
				default_format = default_format.before(".gz");
				String unzipped_filename;
				File::createTemporaryFilename(unzipped_filename, default_format);
				filename = unzipped_filename;
			}

			if (default_format == "ac")
			{
				file = new AntechamberFile(filename, open_mode);
			}
			else if(default_format == "pdb" || default_format == "ent" || default_format == "brk")
			{
				file = new PDBFile(filename, open_mode);
			}
			else if(default_format == "hin")
			{
				file = new HINFile(filename, open_mode);
			}
			else if(default_format == "mol")
			{
				file = new MOLFile(filename, open_mode);
			}
			else if(default_format == "sdf")
			{
				file = new SDFile(filename, open_mode);
			}
			else if(default_format == "mol2")
			{
				file = new MOL2File(filename, open_mode);
			}
			else if(default_format == "xyz")
			{
				file = new XYZFile(filename, open_mode);
			}
			else if(default_format == "drf")
			{
				file = new DockResultFile(filename, open_mode);
			}
			// Make sure that temporary output-file is compressed and then deleted when GenericMolFile is closed.
			if (compression)
			{
				file->enableOutputCompression(zipped_filename);
			}
		}
		return file;
	}

	GenericMolFile* MolFileFactory::open(const String& name, File::OpenMode open_mode, GenericMolFile* default_format_file)
	{
		GenericMolFile* file = open(name, open_mode);
		if (file)
		{
			return file;
		}

		if (open_mode == std::ios::out)
		{
			bool compression = false;
			String filename = name;
			String zipped_filename = "";
			if (default_format_file->isCompressedFile())
			{
				compression = true;
				zipped_filename = filename;
				String unzipped_filename;
				File::createTemporaryFilename(unzipped_filename);
				filename = unzipped_filename;
			}

			if (dynamic_cast<AntechamberFile*>(default_format_file))
			{
				file = new AntechamberFile(filename, open_mode);
			}
			else if(dynamic_cast<PDBFile*>(default_format_file))
			{
				file = new PDBFile(filename, open_mode);
			}
			else if(dynamic_cast<HINFile*>(default_format_file))
			{
				file = new HINFile(filename, open_mode);
			}
			else if(dynamic_cast<SDFile*>(default_format_file))
			{
				file = new SDFile(filename, open_mode);
			}
			else if(dynamic_cast<MOL2File*>(default_format_file))
			{
				file = new MOL2File(filename, open_mode);
			}
			else if(dynamic_cast<MOLFile*>(default_format_file))
			{
				file = new MOLFile(filename, open_mode);
			}
			else if(dynamic_cast<XYZFile*>(default_format_file))
			{
				file = new XYZFile(filename, open_mode);
			}
			else if(dynamic_cast<DockResultFile*>(default_format_file))
			{
				file = new DockResultFile(filename, open_mode);
			}
			// Make sure that temporary output-file is compressed and then deleted when GenericMolFile is closed.
			if (compression)
			{
				file->enableOutputCompression(zipped_filename);
			}
		}
		return file;
	}

	String MolFileFactory::getSupportedFormats()
	{
		String formats = "mol2,sdf,drf,pdb,ac,ent,brk,hin,mol,xyz,mol2.gz,sdf.gz,drf.gz,pdb.gz,ac.gz,ent.gz,brk.gz,hin.gz,mol.gz,xyz.gz";
		return formats;
	}

	GenericMolFile* MolFileFactory::detectFormat(const String& name)
	{
		LineBasedFile input(name, std::ios::in);
		bool empty_file = true;

		// Read at most 400 lines.
		// If no format-indicator is found, return NULL
		for (Size no=1; no < 400 && input.readLine(); no++)
		{
			String& line = input.getLine();
			if (!line.trim().empty())
			{
				empty_file = false;
			}
			if (line.hasPrefix("@<TRIPOS>MOLECULE"))
			{
				input.close();
				return new MOL2File(name, std::ios::in);
			}
			else if (line.hasPrefix("$$$$") || line.hasPrefix("M  END"))
			{
				input.close();
				return new SDFile(name, std::ios::in);
			}
			else if (line.hasPrefix("<dockingfile>"))
			{
				input.close();
				return new DockResultFile(name, std::ios::in);
			}
			else if (line.hasPrefix("HEADER") || line.hasPrefix("ATOM") || line.hasPrefix("USER"))
			{
				input.close();
				return new PDBFile(name, std::ios::in);
			}
		}

		if (empty_file)
		{
			Log.error() << std::endl << "[Error:] Specified input file is empty!" << std::endl << std::endl;
		}
		else
		{
			Log.error() << std::endl << "[Error:] Specified input file has unknown extension and its format could not be detected automatically!" << std::endl << std::endl;
		}

		input.close();

		return NULL;
	}
}

<|endoftext|>


<commit_before>// This file generated by nlsinfo -H -N FBNLS ../src ../util, on Mon Jun 21 00:15:24 2004

#ifndef FLUXBOX_NLS_HH
#define FLUXBOX_NLS_HH

namespace FBNLS {

enum {
	AlignSet = 1,
	AlignBottomCenter = 1,
	AlignBottomLeft = 2,
	AlignBottomRight = 3,
	AlignHorizontal = 4,
	AlignLeft = 5,
	AlignLeftBottom = 6,
	AlignLeftCenter = 7,
	AlignLeftTop = 8,
	AlignRelative = 9,
	AlignRight = 10,
	AlignRightBottom = 11,
	AlignRightCenter = 12,
	AlignRightTop = 13,
	AlignTopCenter = 14,
	AlignTopLeft = 15,
	AlignTopRight = 16,
	AlignVertical = 17,

	BaseDisplaySet = 2,
	BaseDisplayAborting = 1,
	BaseDisplayShuttingDown = 2,
	BaseDisplaySignalCaught = 3,

	CommonSet = 3,
	CommonAlpha = 1,
	CommonAutoHide = 2,
	CommonCompiled = 3,
	CommonCompiledOptions = 4,
	CommonCompiler = 5,
	CommonCompilerVersion = 6,
	CommonDefaultInitFile = 7,
	CommonDefaultKeyFile = 8,
	CommonDefaultMenuFile = 9,
	CommonDefaultStyle = 10,
	CommonDefaults = 11,
	CommonDisabled = 12,
	CommonError = 13,
	CommonFluxboxVersion = 14,
	CommonMaximizeOver = 15,
	CommonVisible = 16,

	ConfigmenuSet = 4,
	ConfigmenuAntiAlias = 1,
	ConfigmenuAutoRaise = 2,
	ConfigmenuClickRaises = 3,
	ConfigmenuClickToFocus = 4,
	ConfigmenuDecorateTransient = 5,
	ConfigmenuDesktopWheeling = 6,
	ConfigmenuFocusLast = 7,
	ConfigmenuFocusModel = 8,
	ConfigmenuFocusNew = 9,
	ConfigmenuFullMax = 10,
	ConfigmenuImageDithering = 11,
	ConfigmenuOpaqueMove = 12,
	ConfigmenuSemiSloppyFocus = 13,
	ConfigmenuSloppyFocus = 14,
	ConfigmenuWorkspaceWarping = 15,

	EwmhSet = 5,
	EwmhOutOfMemoryClientList = 1,

	FbTkErrorSet = 6,
	FbTkErrorBigHeight = 1,
	FbTkErrorBigWidth = 2,
	FbTkErrorCantFallbackFont = 3,
	FbTkErrorColorAllocation = 4,
	FbTkErrorCreatePixmap = 5,
	FbTkErrorCreateXImage = 6,
	FbTkErrorFailedRead = 7,
	FbTkErrorNoRenderFormat = 8,
	FbTkErrorNoRenderPicture = 9,
	FbTkErrorNoRenderPixmap = 10,
	FbTkErrorNoRenderVisualFormat = 11,
	FbTkErrorOutOfMemory = 12,
	FbTkErrorOutOfMemoryBlue = 13,
	FbTkErrorOutOfMemoryGreen = 14,
	FbTkErrorOutOfMemoryRed = 15,
	FbTkErrorThemeItem = 16,
	FbTkErrorUnsupportedVisual = 17,
	FbTkErrorUsingDefault = 18,

	FluxboxSet = 7,
	FluxboxBadRCFile = 1,
	FluxboxCantLoadGroupFile = 2,
	FluxboxCantLoadRCFile = 3,
	FluxboxCantLoadRCFileTrying = 4,
	FluxboxCantMapWindow = 5,
	FluxboxErrorCreatingDirectory = 6,
	FluxboxErrorNoScreens = 7,
	FluxboxErrorRegexp = 8,
	FluxboxFatalSingleton = 9,
	FluxboxNoDisplay = 10,
	FluxboxWarningLocale = 11,
	FluxboxWarningLocaleModifiers = 12,

	GnomeSet = 8,
	GnomeOutOfMemoryClientList = 1,

	KeysSet = 9,
	KeysBadLine = 1,
	KeysBadMerge = 2,
	KeysInvalidKeyMod = 3,

	MenuSet = 10,
	MenuConfiguration = 1,
	MenuDefaultRootMenu = 2,
	MenuExit = 3,
	MenuIcons = 4,
	MenuLayer = 5,
	MenuOnHead = 6,
	MenuPlacement = 7,
	MenuReconfigure = 8,
	MenuRestart = 9,
	Menuxterm = 10,

	RememberSet = 11,
	RememberDecorations = 1,
	RememberDimensions = 2,
	RememberJumpToWorkspace = 3,
	RememberLayer = 4,
	RememberMenuItemName = 5,
	RememberPosition = 6,
	RememberSaveOnClose = 7,
	RememberShaded = 8,
	RememberSticky = 9,
	RememberUnknown = 10,
	RememberWorkspace = 11,

	ScreenSet = 12,
	ScreenAnotherWMRunning = 1,
	ScreenGeometryFormat = 2,
	ScreenGeometryLength = 3,
	ScreenManagingScreen = 4,
	ScreenPositionFormat = 5,
	ScreenPositionLength = 6,

	SlitSet = 13,
	SlitClientsMenu = 1,
	SlitCycleDown = 2,
	SlitCycleUp = 3,
	SlitDirection = 4,
	SlitLayer = 5,
	SlitOnHead = 6,
	SlitPlacement = 7,
	SlitSlit = 8,

	ToolbarSet = 14,
	ToolbarEditWkspcName = 1,
	ToolbarIconbarMode = 2,
	ToolbarIconbarModeAllWindows = 3,
	ToolbarIconbarModeIcons = 4,
	ToolbarIconbarModeNone = 5,
	ToolbarIconbarModeWorkspace = 6,
	ToolbarIconbarModeWorkspaceIcons = 7,
	ToolbarLayer = 8,
	ToolbarOnHead = 9,
	ToolbarPlacement = 10,
	ToolbarToolbar = 11,
	ToolbarWidthPercent = 12,

	WindowSet = 15,
	WindowUnnamed = 1,

	WindowmenuSet = 16,
	WindowmenuClose = 1,
	WindowmenuIconify = 2,
	WindowmenuLayer = 3,
	WindowmenuLower = 4,
	WindowmenuMaximize = 5,
	WindowmenuRaise = 6,
	WindowmenuSendTo = 7,
	WindowmenuShade = 8,
	WindowmenuStick = 9,

	WorkspaceSet = 17,
	WorkspaceDefaultNameFormat = 1,
	WorkspaceMenuTitle = 2,
	WorkspaceNewWorkspace = 3,
	WorkspaceRemoveLast = 4,

	bsetrootSet = 18,
	bsetrootMustSpecify = 1,
	bsetrootNoPixmapAtoms = 2,
	bsetrootUsage = 3,

	mainSet = 19,
	mainDISPLAYRequiresArg = 1,
	mainErrorBadAlloc = 2,
	mainErrorBadCast = 3,
	mainErrorOutOfRange = 4,
	mainErrorRuntime = 5,
	mainErrorStandardException = 6,
	mainErrorUnknown = 7,
	mainLOGRequiresArg = 8,
	mainLogFile = 9,
	mainLoggingTo = 10,
	mainRCRequiresArg = 11,
	mainUsage = 12,
	mainWarnDisplaySet = 13,

	LayerSet = 20,
	LayerAboveDock = 1,
	LayerBottom = 2,
	LayerDesktop = 3,
	LayerDock = 4,
	LayerNormal = 5,
	LayerTop = 6,

	dummy_not_used = 0 // just for the end

}; // end enum

}; // end namespace FBNLS

#endif // FLUXBOX_NLS_HH
<commit_msg>little string update<commit_after>// This file generated by nlsinfo -H -N FBNLS ../src ../util, on Mon Jun 21 00:15:24 2004

#ifndef FLUXBOX_NLS_HH
#define FLUXBOX_NLS_HH

namespace FBNLS {

enum {
	AlignSet = 1,
	AlignBottomCenter = 1,
	AlignBottomLeft = 2,
	AlignBottomRight = 3,
	AlignHorizontal = 4,
	AlignLeft = 5,
	AlignLeftBottom = 6,
	AlignLeftCenter = 7,
	AlignLeftTop = 8,
	AlignRelative = 9,
	AlignRight = 10,
	AlignRightBottom = 11,
	AlignRightCenter = 12,
	AlignRightTop = 13,
	AlignTopCenter = 14,
	AlignTopLeft = 15,
	AlignTopRight = 16,
	AlignVertical = 17,

	BaseDisplaySet = 2,
	BaseDisplayAborting = 1,
	BaseDisplayShuttingDown = 2,
	BaseDisplaySignalCaught = 3,

	CommonSet = 3,
	CommonAlpha = 1,
	CommonAutoHide = 2,
	CommonCompiled = 3,
	CommonCompiledOptions = 4,
	CommonCompiler = 5,
	CommonCompilerVersion = 6,
	CommonDefaultInitFile = 7,
	CommonDefaultKeyFile = 8,
	CommonDefaultMenuFile = 9,
	CommonDefaultStyle = 10,
	CommonDefaults = 11,
	CommonDisabled = 12,
	CommonError = 13,
	CommonFluxboxVersion = 14,
	CommonMaximizeOver = 15,
	CommonVisible = 16,

	ConfigmenuSet = 4,
	ConfigmenuAntiAlias = 1,
	ConfigmenuAutoRaise = 2,
	ConfigmenuClickRaises = 3,
	ConfigmenuClickToFocus = 4,
	ConfigmenuDecorateTransient = 5,
	ConfigmenuDesktopWheeling = 6,
	ConfigmenuFocusLast = 7,
	ConfigmenuFocusModel = 8,
	ConfigmenuFocusNew = 9,
	ConfigmenuFullMax = 10,
	ConfigmenuImageDithering = 11,
	ConfigmenuOpaqueMove = 12,
	ConfigmenuSemiSloppyFocus = 13,
	ConfigmenuSloppyFocus = 14,
	ConfigmenuWorkspaceWarping = 15,
	ConfigmenuForcePseudoTrans = 16,
	ConfigmenuMenuAlpha = 17,

	EwmhSet = 5,
	EwmhOutOfMemoryClientList = 1,

	FbTkErrorSet = 6,
	FbTkErrorBigHeight = 1,
	FbTkErrorBigWidth = 2,
	FbTkErrorCantFallbackFont = 3,
	FbTkErrorColorAllocation = 4,
	FbTkErrorCreatePixmap = 5,
	FbTkErrorCreateXImage = 6,
	FbTkErrorFailedRead = 7,
	FbTkErrorNoRenderFormat = 8,
	FbTkErrorNoRenderPicture = 9,
	FbTkErrorNoRenderPixmap = 10,
	FbTkErrorNoRenderVisualFormat = 11,
	FbTkErrorOutOfMemory = 12,
	FbTkErrorOutOfMemoryBlue = 13,
	FbTkErrorOutOfMemoryGreen = 14,
	FbTkErrorOutOfMemoryRed = 15,
	FbTkErrorThemeItem = 16,
	FbTkErrorUnsupportedVisual = 17,
	FbTkErrorUsingDefault = 18,

	FluxboxSet = 7,
	FluxboxBadRCFile = 1,
	FluxboxCantLoadGroupFile = 2,
	FluxboxCantLoadRCFile = 3,
	FluxboxCantLoadRCFileTrying = 4,
	FluxboxCantMapWindow = 5,
	FluxboxErrorCreatingDirectory = 6,
	FluxboxErrorNoScreens = 7,
	FluxboxErrorRegexp = 8,
	FluxboxFatalSingleton = 9,
	FluxboxNoDisplay = 10,
	FluxboxWarningLocale = 11,
	FluxboxWarningLocaleModifiers = 12,

	GnomeSet = 8,
	GnomeOutOfMemoryClientList = 1,

	KeysSet = 9,
	KeysBadLine = 1,
	KeysBadMerge = 2,
	KeysInvalidKeyMod = 3,

	MenuSet = 10,
	MenuConfiguration = 1,
	MenuDefaultRootMenu = 2,
	MenuExit = 3,
	MenuIcons = 4,
	MenuLayer = 5,
	MenuOnHead = 6,
	MenuPlacement = 7,
	MenuReconfigure = 8,
	MenuRestart = 9,
	Menuxterm = 10,

	RememberSet = 11,
	RememberDecorations = 1,
	RememberDimensions = 2,
	RememberJumpToWorkspace = 3,
	RememberLayer = 4,
	RememberMenuItemName = 5,
	RememberPosition = 6,
	RememberSaveOnClose = 7,
	RememberShaded = 8,
	RememberSticky = 9,
	RememberUnknown = 10,
	RememberWorkspace = 11,

	ScreenSet = 12,
	ScreenAnotherWMRunning = 1,
	ScreenGeometryFormat = 2,
	ScreenGeometryLength = 3,
	ScreenManagingScreen = 4,
	ScreenPositionFormat = 5,
	ScreenPositionLength = 6,

	SlitSet = 13,
	SlitClientsMenu = 1,
	SlitCycleDown = 2,
	SlitCycleUp = 3,
	SlitDirection = 4,
	SlitLayer = 5,
	SlitOnHead = 6,
	SlitPlacement = 7,
	SlitSlit = 8,

	ToolbarSet = 14,
	ToolbarEditWkspcName = 1,
	ToolbarIconbarMode = 2,
	ToolbarIconbarModeAllWindows = 3,
	ToolbarIconbarModeIcons = 4,
	ToolbarIconbarModeNone = 5,
	ToolbarIconbarModeWorkspace = 6,
	ToolbarIconbarModeWorkspaceIcons = 7,
	ToolbarLayer = 8,
	ToolbarOnHead = 9,
	ToolbarPlacement = 10,
	ToolbarToolbar = 11,
	ToolbarWidthPercent = 12,

	WindowSet = 15,
	WindowUnnamed = 1,

	WindowmenuSet = 16,
	WindowmenuClose = 1,
	WindowmenuIconify = 2,
	WindowmenuLayer = 3,
	WindowmenuLower = 4,
	WindowmenuMaximize = 5,
	WindowmenuRaise = 6,
	WindowmenuSendTo = 7,
	WindowmenuShade = 8,
	WindowmenuStick = 9,

	WorkspaceSet = 17,
	WorkspaceDefaultNameFormat = 1,
	WorkspaceMenuTitle = 2,
	WorkspaceNewWorkspace = 3,
	WorkspaceRemoveLast = 4,

	bsetrootSet = 18,
	bsetrootMustSpecify = 1,
	bsetrootNoPixmapAtoms = 2,
	bsetrootUsage = 3,

	mainSet = 19,
	mainDISPLAYRequiresArg = 1,
	mainErrorBadAlloc = 2,
	mainErrorBadCast = 3,
	mainErrorOutOfRange = 4,
	mainErrorRuntime = 5,
	mainErrorStandardException = 6,
	mainErrorUnknown = 7,
	mainLOGRequiresArg = 8,
	mainLogFile = 9,
	mainLoggingTo = 10,
	mainRCRequiresArg = 11,
	mainUsage = 12,
	mainWarnDisplaySet = 13,

	LayerSet = 20,
	LayerAboveDock = 1,
	LayerBottom = 2,
	LayerDesktop = 3,
	LayerDock = 4,
	LayerNormal = 5,
	LayerTop = 6,

	dummy_not_used = 0 // just for the end

}; // end enum

}; // end namespace FBNLS

#endif // FLUXBOX_NLS_HH
<|endoftext|>


<commit_before>/*++
Copyright (c) 2013 Microsoft Corporation

Module Name:

    optimize_objectives.cpp

Abstract:

    Objective optimization method.

Author:

    Anh-Dung Phan (t-anphan) 2013-10-16

Notes:

    Suppose we obtain solution t1 = k1, ..., tn = kn-epsilon
    Assert:
      t1 > k1 \/ t2 > k2 \/ ... \/ tn >= kn
    If this solution is satisfiable, then for each t_i, maximize the
    assignment and assert the new frontier.
    Claim: we don't necessarily have to freeze assignments of
    t_i when optimizing assignment for t_j
    because the state will always satisfy the disjunction.
    If one of the k_i is unbounded, then omit a disjunction for it.
    Claim: the end result (when the constraints are no longer feasible)
    is Pareto optimal, but convergence will probably not be as fast
    as when fixing one parameter at a time.
    E.g., a different approach is first to find a global maximal for one
    variable. Then add a method to "freeze" that variable at the extremum if it is finite.
    To do this, add lower and upper bounds for that variable using infinitesimals.
    If the variable is unbounded, then this is of course not sufficient by itself.

--*/

#ifndef _OPT_OBJECTIVE_H_
#define _OPT_OBJECTIVE_H_

#include "optimize_objectives.h"
#include "opt_solver.h"
#include "arith_decl_plugin.h"
#include "theory_arith.h"
#include "ast_pp.h"
#include "model_pp.h"

namespace opt {

    void optimize_objectives::set_cancel(bool f) {
        m_cancel = true;
    }

    void optimize_objectives::set_max(vector<inf_eps>& dst, vector<inf_eps> const& src) {
        for (unsigned i = 0; i < src.size(); ++i) {
            if (src[i] > dst[i]) {
                dst[i] = src[i];
            }
        }
    }

    /*
        Enumerate locally optimal assignments until fixedpoint.
    */
    lbool optimize_objectives::basic_opt(app_ref_vector& objectives) {
        arith_util autil(m);

        opt_solver::scoped_push _push(*s);

        for (unsigned i = 0; i < objectives.size(); ++i) {
            m_vars.push_back(s->add_objective(objectives[i].get()));
        }

        lbool is_sat = l_true;
        // ready to test:
        is_sat = update_upper();
        opt_solver::toggle_objective _t(*s, true);

        while (is_sat == l_true && !m_cancel) {
            is_sat = update_lower();
        }

        if (m_cancel || is_sat == l_undef) {
            return l_undef;
        }
        return l_true;
    }

    lbool optimize_objectives::update_lower() {
        lbool is_sat = s->check_sat(0, 0);
        if (is_sat == l_true) {
            model_ref md;
            s->get_model(md);
            set_max(m_lower, s->get_objective_values());
            IF_VERBOSE(1,
                       for (unsigned i = 0; i < m_lower.size(); ++i) {
                           verbose_stream() << m_lower[i] << " ";
                       }
                       verbose_stream() << "\n";
                       // model_pp(verbose_stream(), *md);
                       );
            expr_ref_vector disj(m);
            expr_ref constraint(m);

            for (unsigned i = 0; i < m_lower.size(); ++i) {
                inf_eps const& v = m_lower[i];
                disj.push_back(s->block_lower_bound(i, v));
            }
            constraint = m.mk_or(disj.size(), disj.c_ptr());
            s->assert_expr(constraint);
        }
        return is_sat;
    }

    lbool optimize_objectives::update_upper() {
        smt::theory_opt& opt = s->get_optimizer();

        IF_VERBOSE(1, verbose_stream() << typeid(opt).name() << "\n";);
        if (typeid(smt::theory_inf_arith) != typeid(opt)) {
            return l_true;
        }
        smt::theory_inf_arith& th = dynamic_cast<smt::theory_inf_arith&>(opt);

        expr_ref bound(m);
        expr_ref_vector bounds(m);

        opt_solver::scoped_push _push(*s);
        //
        // NB: we have to create all bound expressions before calling check_sat
        // because the state after check_sat is not at base level.
        //

        for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
            if (m_lower[i] < m_upper[i]) {
                SASSERT(m_upper[i].get_infinity().is_pos());
                smt::theory_var v = m_vars[i];
                bound = th.block_upper_bound(v, m_upper[i]);
                bounds.push_back(bound);
            }
            else {
                bounds.push_back(0);
            }
        }
        for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
            if (m_lower[i] < m_upper[i]) {
                lbool is_sat = s->check_sat(1, bounds.c_ptr() + i);
                if (is_sat == l_true) {
                    IF_VERBOSE(2, verbose_stream() << "Setting lower bound for v" << m_vars[i] << " to " << m_upper[i] << "\n";);
                    m_lower[i] = m_upper[i];
                }
                else if (is_sat == l_false) {
                    // else: TBD extract Farkas coefficients.
                }
            }
        }
        return l_true;
    }

    /**
       Takes solver with hard constraints added.
       Returns an optimal assignment to objective functions.
    */
    lbool optimize_objectives::operator()(opt_solver& solver, app_ref_vector& objectives, vector<inf_eps>& values) {
        s = &solver;
        s->reset_objectives();
        m_lower.reset();
        m_upper.reset();
        for (unsigned i = 0; i < objectives.size(); ++i) {
            m_lower.push_back(inf_eps(rational(-1),inf_rational(0)));
            m_upper.push_back(inf_eps(rational(1), inf_rational(0)));
        }

        // First check_sat call to initialize theories
        lbool is_sat = s->check_sat(0, 0);
        if (is_sat == l_true) {
            is_sat = basic_opt(objectives);
            values.reset();
            values.append(m_lower);
        }
        return is_sat;
    }

}

#endif
<commit_msg>debugging infinite upper bound checking<commit_after>/*++
Copyright (c) 2013 Microsoft Corporation

Module Name:

    optimize_objectives.cpp

Abstract:

    Objective optimization method.

Author:

    Anh-Dung Phan (t-anphan) 2013-10-16

Notes:

    Suppose we obtain solution t1 = k1, ..., tn = kn-epsilon
    Assert:
      t1 > k1 \/ t2 > k2 \/ ... \/ tn >= kn
    If this solution is satisfiable, then for each t_i, maximize the
    assignment and assert the new frontier.
    Claim: we don't necessarily have to freeze assignments of
    t_i when optimizing assignment for t_j
    because the state will always satisfy the disjunction.
    If one of the k_i is unbounded, then omit a disjunction for it.
    Claim: the end result (when the constraints are no longer feasible)
    is Pareto optimal, but convergence will probably not be as fast
    as when fixing one parameter at a time.
    E.g., a different approach is first to find a global maximal for one
    variable. Then add a method to "freeze" that variable at the extremum if it is finite.
    To do this, add lower and upper bounds for that variable using infinitesimals.
    If the variable is unbounded, then this is of course not sufficient by itself.

--*/

#ifndef _OPT_OBJECTIVE_H_
#define _OPT_OBJECTIVE_H_

#include "optimize_objectives.h"
#include "opt_solver.h"
#include "arith_decl_plugin.h"
#include "theory_arith.h"
#include "ast_pp.h"
#include "model_pp.h"

namespace opt {

    void optimize_objectives::set_cancel(bool f) {
        m_cancel = true;
    }

    void optimize_objectives::set_max(vector<inf_eps>& dst, vector<inf_eps> const& src) {
        for (unsigned i = 0; i < src.size(); ++i) {
            if (src[i] > dst[i]) {
                dst[i] = src[i];
            }
        }
    }

    /*
        Enumerate locally optimal assignments until fixedpoint.
    */
    lbool optimize_objectives::basic_opt(app_ref_vector& objectives) {
        arith_util autil(m);

        opt_solver::scoped_push _push(*s);

        for (unsigned i = 0; i < objectives.size(); ++i) {
            m_vars.push_back(s->add_objective(objectives[i].get()));
        }

        lbool is_sat = l_true;
        // Disabled while testing and tuning:
        // is_sat = update_upper();
        opt_solver::toggle_objective _t(*s, true);

        while (is_sat == l_true && !m_cancel) {
            is_sat = update_lower();
        }

        if (m_cancel || is_sat == l_undef) {
            return l_undef;
        }
        return l_true;
    }

    lbool optimize_objectives::update_lower() {
        lbool is_sat = s->check_sat(0, 0);
        if (is_sat == l_true) {
            model_ref md;
            s->get_model(md);
            set_max(m_lower, s->get_objective_values());
            IF_VERBOSE(1,
                       for (unsigned i = 0; i < m_lower.size(); ++i) {
                           verbose_stream() << m_lower[i] << " ";
                       }
                       verbose_stream() << "\n";
                       // model_pp(verbose_stream(), *md);
                       );
            expr_ref_vector disj(m);
            expr_ref constraint(m);

            for (unsigned i = 0; i < m_lower.size(); ++i) {
                inf_eps const& v = m_lower[i];
                disj.push_back(s->block_lower_bound(i, v));
            }
            constraint = m.mk_or(disj.size(), disj.c_ptr());
            s->assert_expr(constraint);
        }
        return is_sat;
    }

    lbool optimize_objectives::update_upper() {
        smt::theory_opt& opt = s->get_optimizer();

        IF_VERBOSE(1, verbose_stream() << typeid(opt).name() << "\n";);
        if (typeid(smt::theory_inf_arith) != typeid(opt)) {
            return l_true;
        }
        smt::theory_inf_arith& th = dynamic_cast<smt::theory_inf_arith&>(opt);

        expr_ref bound(m);
        expr_ref_vector bounds(m);

        opt_solver::scoped_push _push(*s);
        //
        // NB: we have to create all bound expressions before calling check_sat
        // because the state after check_sat is not at base level.
        //

        for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
            if (m_lower[i] < m_upper[i]) {
                SASSERT(m_upper[i].get_infinity().is_pos());
                smt::theory_var v = m_vars[i];
                bound = th.block_upper_bound(v, m_upper[i]);
                bounds.push_back(bound);
            }
            else {
                bounds.push_back(0);
            }
        }
        for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
            if (m_lower[i] < m_upper[i]) {
                lbool is_sat = s->check_sat(1, bounds.c_ptr() + i);
                if (is_sat == l_true) {
                    IF_VERBOSE(2, verbose_stream() << "Setting lower bound for v" << m_vars[i] << " to " << m_upper[i] << "\n";);
                    m_lower[i] = m_upper[i];
                }
                else if (is_sat == l_false) {
                    // else: TBD extract Farkas coefficients.
                }
            }
        }
        return l_true;
    }

    /**
       Takes solver with hard constraints added.
       Returns an optimal assignment to objective functions.
    */
    lbool optimize_objectives::operator()(opt_solver& solver, app_ref_vector& objectives, vector<inf_eps>& values) {
        s = &solver;
        s->reset_objectives();
        m_lower.reset();
        m_upper.reset();
        for (unsigned i = 0; i < objectives.size(); ++i) {
            m_lower.push_back(inf_eps(rational(-1),inf_rational(0)));
            m_upper.push_back(inf_eps(rational(1), inf_rational(0)));
        }

        // First check_sat call to initialize theories
        lbool is_sat = s->check_sat(0, 0);
        if (is_sat == l_true) {
            is_sat = basic_opt(objectives);
            values.reset();
            values.append(m_lower);
        }
        return is_sat;
    }

}

#endif
<|endoftext|>


<commit_before>#include "NativeToolsItems.h"
#include "Barrier.h"

#include "../creative/CreativeTab.h"

Item* NativeToolsItems::barrier;

void NativeToolsItems::initItems()
{
	barrier = new Barrier("barrier", 420);

	CreativeTab* myTab1 = new CreativeTab();
	myTab1->addItem(4, 0);
	myTab1->addItem(11, 0);
	myTab1->addItem(4, 0);
	myTab1->addItem(110, 0);
	myTab1->addItem(5, 0);
	myTab1->addItem(11, 0);
	myTab1->addItem(46, 0);
	myTab1->addItem(49, 0);
	myTab1->addItem(4, 0);
	myTab1->addItem(11, 0);
	myTab1->addItem(4, 0);
	myTab1->addItem(110, 0);
	myTab1->addItem(5, 0);
	myTab1->addItem(11, 0);
	myTab1->addItem(46, 0);
	myTab1->addItem(49, 0);
	myTab1->addToTabsList();
	CreativeTab* myTab2 = new CreativeTab();
	myTab2->addItem(4, 0);
	myTab2->addItem(110, 0);
	myTab2->addItem(5, 0);
	myTab2->addItem(11, 0);
	myTab2->addItem(5, 0);
	myTab2->addItem(11, 0);
	myTab2->addItem(46, 0);
	myTab2->addItem(49, 0);
	myTab2->addItem(4, 0);
	myTab2->addItem(11, 0);
	myTab2->addItem(4, 0);
	myTab2->addItem(110, 0);
	myTab2->addItem(11, 0);
	myTab2->addItem(46, 0);
	myTab2->addItem(49, 0);
	myTab2->addItem(4, 0);
	myTab2->addToTabsList();
	CreativeTab* myTab3 = new CreativeTab();
	myTab3->addItem(5, 0);
	myTab3->addItem(11, 0);
	myTab3->addItem(5, 0);
	myTab3->addItem(4, 0);
	myTab3->addItem(110, 0);
	myTab3->addItem(49, 0);
	myTab3->addItem(4, 0);
	myTab3->addItem(11, 0);
	myTab3->addItem(110, 0);
	myTab3->addItem(11, 0);
	myTab3->addItem(46, 0);
	myTab3->addItem(4, 0);
	myTab3->addItem(11, 0);
	myTab3->addItem(46, 0);
	myTab3->addItem(49, 0);
	myTab3->addItem(4, 0);
	myTab3->addToTabsList();
	CreativeTab* myTab4 = new CreativeTab();
	myTab4->addItem(5, 0);
	myTab4->addItem(4, 0);
	myTab4->addItem(110, 0);
	myTab4->addItem(46, 0);
	myTab4->addItem(49, 0);
	myTab4->addItem(5, 0);
	myTab4->addItem(11, 0);
	myTab4->addItem(4, 0);
	myTab4->addItem(11, 0);
	myTab4->addItem(110, 0);
	myTab4->addItem(49, 0);
	myTab4->addItem(11, 0);
	myTab4->addItem(46, 0);
	myTab4->addItem(4, 0);
	myTab4->addItem(11, 0);
	myTab4->addItem(4, 0);
	myTab4->addToTabsList();
	CreativeTab* myTab5 = new CreativeTab();
	myTab5->addItem(11, 0);
	myTab5->addItem(11, 0);
	myTab5->addItem(4, 0);
	myTab5->addItem(4, 0);
	myTab5->addItem(49, 0);
	myTab5->addItem(5, 0);
	myTab5->addItem(5, 0);
	myTab5->addItem(110, 0);
	myTab5->addItem(46, 0);
	myTab5->addItem(4, 0);
	myTab5->addItem(4, 0);
	myTab5->addItem(11, 0);
	myTab5->addItem(110, 0);
	myTab5->addItem(49, 0);
	myTab5->addItem(11, 0);
	myTab5->addItem(46, 0);
	myTab5->addToTabsList();
}<commit_msg>Item icon api works perfectly!<commit_after>#include "NativeToolsItems.h"
#include "Barrier.h"

#include "../creative/CreativeTab.h"

Item* NativeToolsItems::barrier;

void NativeToolsItems::initItems()
{
	barrier = new Barrier("barrier", 420);

	CreativeTab* myTab1 = new CreativeTab(257, 0);
	myTab1->addItem(4, 0);
	myTab1->addItem(11, 0);
	myTab1->addItem(4, 0);
	myTab1->addItem(110, 0);
	myTab1->addItem(5, 0);
	myTab1->addItem(11, 0);
	myTab1->addItem(46, 0);
	myTab1->addItem(49, 0);
	myTab1->addItem(4, 0);
	myTab1->addItem(11, 0);
	myTab1->addItem(4, 0);
	myTab1->addItem(110, 0);
	myTab1->addItem(5, 0);
	myTab1->addItem(11, 0);
	myTab1->addItem(46, 0);
	myTab1->addItem(49, 0);
	myTab1->addToTabsList();
	CreativeTab* myTab2 = new CreativeTab(261, 0);
	myTab2->addItem(4, 0);
	myTab2->addItem(110, 0);
	myTab2->addItem(5, 0);
	myTab2->addItem(11, 0);
	myTab2->addItem(5, 0);
	myTab2->addItem(11, 0);
	myTab2->addItem(46, 0);
	myTab2->addItem(49, 0);
	myTab2->addItem(4, 0);
	myTab2->addItem(11, 0);
	myTab2->addItem(4, 0);
	myTab2->addItem(110, 0);
	myTab2->addItem(11, 0);
	myTab2->addItem(46, 0);
	myTab2->addItem(49, 0);
	myTab2->addItem(4, 0);
	myTab2->addToTabsList();
	CreativeTab* myTab3 = new CreativeTab(260, 0);
	myTab3->addItem(5, 0);
	myTab3->addItem(11, 0);
	myTab3->addItem(5, 0);
	myTab3->addItem(4, 0);
	myTab3->addItem(110, 0);
	myTab3->addItem(49, 0);
	myTab3->addItem(4, 0);
	myTab3->addItem(11, 0);
	myTab3->addItem(110, 0);
	myTab3->addItem(11, 0);
	myTab3->addItem(46, 0);
	myTab3->addItem(4, 0);
	myTab3->addItem(11, 0);
	myTab3->addItem(46, 0);
	myTab3->addItem(49, 0);
	myTab3->addItem(4, 0);
	myTab3->addToTabsList();
	CreativeTab* myTab4 = new CreativeTab(265, 0);
	myTab4->addItem(5, 0);
	myTab4->addItem(4, 0);
	myTab4->addItem(110, 0);
	myTab4->addItem(46, 0);
	myTab4->addItem(49, 0);
	myTab4->addItem(5, 0);
	myTab4->addItem(11, 0);
	myTab4->addItem(4, 0);
	myTab4->addItem(11, 0);
	myTab4->addItem(110, 0);
	myTab4->addItem(49, 0);
	myTab4->addItem(11, 0);
	myTab4->addItem(46, 0);
	myTab4->addItem(4, 0);
	myTab4->addItem(11, 0);
	myTab4->addItem(4, 0);
	myTab4->addToTabsList();
	CreativeTab* myTab5 = new CreativeTab(258, 0);
	myTab5->addItem(11, 0);
	myTab5->addItem(11, 0);
	myTab5->addItem(4, 0);
	myTab5->addItem(4, 0);
	myTab5->addItem(49, 0);
	myTab5->addItem(5, 0);
	myTab5->addItem(5, 0);
	myTab5->addItem(110, 0);
	myTab5->addItem(46, 0);
	myTab5->addItem(4, 0);
	myTab5->addItem(4, 0);
	myTab5->addItem(11, 0);
	myTab5->addItem(110, 0);
	myTab5->addItem(49, 0);
	myTab5->addItem(11, 0);
	myTab5->addItem(46, 0);
	myTab5->addToTabsList();
}<|endoftext|>


<commit_before>/*
  Q Light Controller
  artnetnode.cpp

  Copyright (c) Massimo Callegari

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  Version 2 as published by the Free Software Foundation.

  This program 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 General Public License for more details. The license is
  in the file "COPYING".

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "artnetcontroller.h"

#include <QDebug>

ArtNetController::ArtNetController(QString ipaddr, QList<QNetworkAddressEntry> interfaces,
                                   QList<QString> macAddrList, Type type, QObject *parent)
    : QObject(parent)
{
    m_ipAddr = QHostAddress(ipaddr);

    int i = 0;
    foreach(QNetworkAddressEntry iface, interfaces)
    {
        if (iface.ip() == m_ipAddr)
        {
            m_broadcastAddr = iface.broadcast();
            m_MACAddress = macAddrList.at(i);
            break;
        }
        i++;
    }

    /*
    // calculate the broadcast address
    quint32 ip = m_ipAddr.toIPv4Address();
    quint32 mask = QHostAddress("255.255.255.0").toIPv4Address(); // will it work in all cases ?
    quint32 broadcast = (ip & mask) | (0xFFFFFFFFU & ~mask);
    m_broadcastAddr = QHostAddress(broadcast);
    */

    qDebug() << "[ArtNetController] Broadcast address:" << m_broadcastAddr.toString() << "(MAC:" << m_MACAddress << ")";
    qDebug() << "[ArtNetController] type: " << type;
    m_packetizer = new ArtNetPacketizer();
    m_packetSent = 0;
    m_packetReceived = 0;

    m_UdpSocket = new QUdpSocket(this);
#if defined(__APPLE__)
    if (m_UdpSocket->bind(ARTNET_DEFAULT_PORT, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint) == false)
#else
    if (m_UdpSocket->bind(m_broadcastAddr, ARTNET_DEFAULT_PORT, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint) == false)
#endif
        return;

    connect(m_UdpSocket, SIGNAL(readyRead()),
            this, SLOT(processPendingPackets()));

    // don't send a Poll if we're an input
    if (type == Output)
    {
        QByteArray pollPacket;
        m_packetizer->setupArtNetPoll(pollPacket);
        qint64 sent = m_UdpSocket->writeDatagram(pollPacket.data(), pollPacket.size(),
                                                 m_broadcastAddr, ARTNET_DEFAULT_PORT);
        if (sent < 0)
        {
            qDebug() << "Unable to send initial Poll packet";
            qDebug() << "Errno: " << m_UdpSocket->error();
            qDebug() << "Errmgs: " << m_UdpSocket->errorString();
        }
        else
            m_packetSent++;
    }
    else
    {
        m_dmxValues.fill(0, 2048);
    }

    m_type = type;
}

ArtNetController::~ArtNetController()
{
    qDebug() << Q_FUNC_INFO;
    disconnect(m_UdpSocket, SIGNAL(readyRead()),
            this, SLOT(processPendingPackets()));
    m_UdpSocket->close();
}

void ArtNetController::addUniverse(quint32 line, int uni)
{
    if (m_universes.contains(uni) == false)
    {
        m_universes[uni] = line;
        qDebug() << "[ArtNetController::addUniverse] Added new universe: " << uni;
    }
}

int ArtNetController::getUniversesNumber()
{
    return m_universes.size();
}

bool ArtNetController::removeUniverse(int uni)
{
    if (m_universes.contains(uni))
    {

        qDebug() << Q_FUNC_INFO << "Removing universe " << uni;
        return m_universes.remove(uni);
    }
    return false;
}

int ArtNetController::getType()
{
    return m_type;
}

quint64 ArtNetController::getPacketSentNumber()
{
    return m_packetSent;
}

quint64 ArtNetController::getPacketReceivedNumber()
{
    return m_packetReceived;
}

QString ArtNetController::getNetworkIP()
{
    return m_ipAddr.toString();
}

QHash<QHostAddress, ArtNetNodeInfo> ArtNetController::getNodesList()
{
    return m_nodesList;
}

void ArtNetController::sendDmx(const int &universe, const QByteArray &data)
{
    QByteArray dmxPacket;
    m_packetizer->setupArtNetDmx(dmxPacket, universe, data);
    qint64 sent = m_UdpSocket->writeDatagram(dmxPacket.data(), dmxPacket.size(),
                                             m_broadcastAddr, ARTNET_DEFAULT_PORT);
    if (sent < 0)
    {
        qDebug() << "sendDmx failed";
        qDebug() << "Errno: " << m_UdpSocket->error();
        qDebug() << "Errmgs: " << m_UdpSocket->errorString();
    }
    else
        m_packetSent++;
}

void ArtNetController::processPendingPackets()
{
    while (m_UdpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        QHostAddress senderAddress;
        datagram.resize(m_UdpSocket->pendingDatagramSize());
        m_UdpSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress);
        if (senderAddress != m_ipAddr)
        {
            qDebug() << "Received packet with size: " << datagram.size() << ", host: " << senderAddress.toString();
            int opCode = -1;
            if (m_packetizer->checkPacketAndCode(datagram, opCode) == true)
            {
                switch (opCode)
                {
                    case ARTNET_POLLREPLY:
                    {
                        qDebug() << "ArtPollReply received";
                        ArtNetNodeInfo newNode;
                        if (m_packetizer->fillArtPollReplyInfo(datagram, newNode) == true)
                        {
                            if (m_nodesList.contains(senderAddress) == false)
                                m_nodesList[senderAddress] = newNode;
                        }
                        QByteArray pollReplyPacket;
                        m_packetizer->setupArtNetPollReply(pollReplyPacket, m_ipAddr, m_MACAddress);
                        m_UdpSocket->writeDatagram(pollReplyPacket.data(), pollReplyPacket.size(),
                                                   senderAddress, ARTNET_DEFAULT_PORT);
                        m_packetReceived++;
                        m_packetSent++;
                    }
                    break;
                    case ARTNET_POLL:
                    {
                        qDebug() << "ArtPoll received";
                        QByteArray pollReplyPacket;
                        m_packetizer->setupArtNetPollReply(pollReplyPacket, m_ipAddr, m_MACAddress);
                        m_UdpSocket->writeDatagram(pollReplyPacket.data(), pollReplyPacket.size(),
                                                   senderAddress, ARTNET_DEFAULT_PORT);
                        m_packetReceived++;
                        m_packetSent++;
                    }
                    break;
                    case ARTNET_DMX:
                    {
                        qDebug() << "DMX data received";
                        QByteArray dmxData;
                        int universe;
                        if (this->getType() == Input)
                        {
                            m_packetReceived++;
                            if (m_packetizer->fillDMXdata(datagram, dmxData, universe) == true)
                            {
                                if ((universe * 512) > m_dmxValues.length() || m_universes.contains(universe) == false)
                                {
                                    qDebug() << "Universe " << universe << "not supported !";
                                    break;
                                }
                                for (int i = 0; i < dmxData.length(); i++)
                                {
                                    if (m_dmxValues.at(i + (universe * 512)) != dmxData.at(i))
                                    {
                                        m_dmxValues[i + (universe * 512)] =  dmxData[i];
                                        emit valueChanged(m_universes[universe], i, (uchar)dmxData.at(i));
                                    }
                                }
                            }
                        }
                    }
                    break;
                    default:
                        qDebug() << "opCode not supported yet (" << opCode << ")";
                        m_packetReceived++;
                    break;
                }
            }
            else
                qDebug() << "Malformed packet received";
        }
     }
}
<commit_msg>ArtNet plugin listens only on port and not port+address. This makes ODE working but can break some multi-input usage<commit_after>/*
  Q Light Controller
  artnetnode.cpp

  Copyright (c) Massimo Callegari

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  Version 2 as published by the Free Software Foundation.

  This program 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 General Public License for more details. The license is
  in the file "COPYING".

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "artnetcontroller.h"

#include <QDebug>

ArtNetController::ArtNetController(QString ipaddr, QList<QNetworkAddressEntry> interfaces,
                                   QList<QString> macAddrList, Type type, QObject *parent)
    : QObject(parent)
{
    m_ipAddr = QHostAddress(ipaddr);

    int i = 0;
    foreach(QNetworkAddressEntry iface, interfaces)
    {
        if (iface.ip() == m_ipAddr)
        {
            m_broadcastAddr = iface.broadcast();
            m_MACAddress = macAddrList.at(i);
            break;
        }
        i++;
    }

    /*
    // calculate the broadcast address
    quint32 ip = m_ipAddr.toIPv4Address();
    quint32 mask = QHostAddress("255.255.255.0").toIPv4Address(); // will it work in all cases ?
    quint32 broadcast = (ip & mask) | (0xFFFFFFFFU & ~mask);
    m_broadcastAddr = QHostAddress(broadcast);
    */

    qDebug() << "[ArtNetController] Broadcast address:" << m_broadcastAddr.toString() << "(MAC:" << m_MACAddress << ")";
    qDebug() << "[ArtNetController] type: " << type;
    m_packetizer = new ArtNetPacketizer();
    m_packetSent = 0;
    m_packetReceived = 0;

    m_UdpSocket = new QUdpSocket(this);

    if (m_UdpSocket->bind(ARTNET_DEFAULT_PORT, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint) == false)
        return;

    connect(m_UdpSocket, SIGNAL(readyRead()),
            this, SLOT(processPendingPackets()));

    // don't send a Poll if we're an input
    if (type == Output)
    {
        QByteArray pollPacket;
        m_packetizer->setupArtNetPoll(pollPacket);
        qint64 sent = m_UdpSocket->writeDatagram(pollPacket.data(), pollPacket.size(),
                                                 m_broadcastAddr, ARTNET_DEFAULT_PORT);
        if (sent < 0)
        {
            qDebug() << "Unable to send initial Poll packet";
            qDebug() << "Errno: " << m_UdpSocket->error();
            qDebug() << "Errmgs: " << m_UdpSocket->errorString();
        }
        else
            m_packetSent++;
    }
    else
    {
        m_dmxValues.fill(0, 2048);
    }

    m_type = type;
}

ArtNetController::~ArtNetController()
{
    qDebug() << Q_FUNC_INFO;
    disconnect(m_UdpSocket, SIGNAL(readyRead()),
            this, SLOT(processPendingPackets()));
    m_UdpSocket->close();
}

void ArtNetController::addUniverse(quint32 line, int uni)
{
    if (m_universes.contains(uni) == false)
    {
        m_universes[uni] = line;
        qDebug() << "[ArtNetController::addUniverse] Added new universe: " << uni;
    }
}

int ArtNetController::getUniversesNumber()
{
    return m_universes.size();
}

bool ArtNetController::removeUniverse(int uni)
{
    if (m_universes.contains(uni))
    {

        qDebug() << Q_FUNC_INFO << "Removing universe " << uni;
        return m_universes.remove(uni);
    }
    return false;
}

int ArtNetController::getType()
{
    return m_type;
}

quint64 ArtNetController::getPacketSentNumber()
{
    return m_packetSent;
}

quint64 ArtNetController::getPacketReceivedNumber()
{
    return m_packetReceived;
}

QString ArtNetController::getNetworkIP()
{
    return m_ipAddr.toString();
}

QHash<QHostAddress, ArtNetNodeInfo> ArtNetController::getNodesList()
{
    return m_nodesList;
}

void ArtNetController::sendDmx(const int &universe, const QByteArray &data)
{
    QByteArray dmxPacket;
    m_packetizer->setupArtNetDmx(dmxPacket, universe, data);
    qint64 sent = m_UdpSocket->writeDatagram(dmxPacket.data(), dmxPacket.size(),
                                             m_broadcastAddr, ARTNET_DEFAULT_PORT);
    if (sent < 0)
    {
        qDebug() << "sendDmx failed";
        qDebug() << "Errno: " << m_UdpSocket->error();
        qDebug() << "Errmgs: " << m_UdpSocket->errorString();
    }
    else
        m_packetSent++;
}

void ArtNetController::processPendingPackets()
{
    while (m_UdpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        QHostAddress senderAddress;
        datagram.resize(m_UdpSocket->pendingDatagramSize());
        m_UdpSocket->readDatagram(datagram.data(), datagram.size(), &senderAddress);
        if (senderAddress != m_ipAddr)
        {
            qDebug() << "Received packet with size: " << datagram.size() << ", host: " << senderAddress.toString();
            int opCode = -1;
            if (m_packetizer->checkPacketAndCode(datagram, opCode) == true)
            {
                switch (opCode)
                {
                    case ARTNET_POLLREPLY:
                    {
                        qDebug() << "ArtPollReply received";
                        ArtNetNodeInfo newNode;
                        if (m_packetizer->fillArtPollReplyInfo(datagram, newNode) == true)
                        {
                            if (m_nodesList.contains(senderAddress) == false)
                                m_nodesList[senderAddress] = newNode;
                        }
                        QByteArray pollReplyPacket;
                        m_packetizer->setupArtNetPollReply(pollReplyPacket, m_ipAddr, m_MACAddress);
                        m_UdpSocket->writeDatagram(pollReplyPacket.data(), pollReplyPacket.size(),
                                                   senderAddress, ARTNET_DEFAULT_PORT);
                        m_packetReceived++;
                        m_packetSent++;
                    }
                    break;
                    case ARTNET_POLL:
                    {
                        qDebug() << "ArtPoll received";
                        QByteArray pollReplyPacket;
                        m_packetizer->setupArtNetPollReply(pollReplyPacket, m_ipAddr, m_MACAddress);
                        m_UdpSocket->writeDatagram(pollReplyPacket.data(), pollReplyPacket.size(),
                                                   senderAddress, ARTNET_DEFAULT_PORT);
                        m_packetReceived++;
                        m_packetSent++;
                    }
                    break;
                    case ARTNET_DMX:
                    {
                        qDebug() << "DMX data received";
                        QByteArray dmxData;
                        int universe;
                        if (this->getType() == Input)
                        {
                            m_packetReceived++;
                            if (m_packetizer->fillDMXdata(datagram, dmxData, universe) == true)
                            {
                                if ((universe * 512) > m_dmxValues.length() || m_universes.contains(universe) == false)
                                {
                                    qDebug() << "Universe " << universe << "not supported !";
                                    break;
                                }
                                for (int i = 0; i < dmxData.length(); i++)
                                {
                                    if (m_dmxValues.at(i + (universe * 512)) != dmxData.at(i))
                                    {
                                        m_dmxValues[i + (universe * 512)] =  dmxData[i];
                                        emit valueChanged(m_universes[universe], i, (uchar)dmxData.at(i));
                                    }
                                }
                            }
                        }
                    }
                    break;
                    default:
                        qDebug() << "opCode not supported yet (" << opCode << ")";
                        m_packetReceived++;
                    break;
                }
            }
            else
                qDebug() << "Malformed packet received";
        }
     }
}
<|endoftext|>


<commit_before>#include "resp.h"
#include <boost/exception/all.hpp>
#include <cassert>

namespace Akumuli {

RESPError::RESPError(std::string msg, int pos)
    : StreamError(msg, pos)
{
}

RESPStream::RESPStream(ByteStreamReader *stream) {
    stream_ = stream;
}

RESPStream::Type RESPStream::next_type() const {
    auto ch = stream_->pick();
    Type result = BAD;
    switch(ch) {
    case '+':
        result = STRING;
        break;
    case ':':
        result = INTEGER;
        break;
    case '$':
        result = BULK_STR;
        break;
    case '*':
        result = ARRAY;
        break;
    case '-':
        result = ERROR;
        break;
    default:
        result = BAD;
        break;
    };
    return result;
}

uint64_t RESPStream::_read_int_body() {
    uint64_t result = 0;
    const int MAX_DIGITS = 84;  // Maximum number of decimal digits in uint64_t
    int quota = MAX_DIGITS;
    while(quota) {
        Byte c = stream_->get();
        if (c == '\r') {
            c = stream_->get();
            if (c == '\n') {
                return result;
            }
            // Bad stream
            auto ctx = stream_->get_error_context("invalid symbol inside stream - '\\r'");
            BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
        }
        // c must be in [0x30:0x39] range
        if (c > 0x39 || c < 0x30) {
            auto ctx = stream_->get_error_context("can't parse integer (character value out of range)");
            BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
        }
        result = result*10 + static_cast<int>(c & 0x0F);
        quota--;
    }
    auto ctx = stream_->get_error_context("integer is too long");
    BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
}

uint64_t RESPStream::read_int() {
    Byte c = stream_->get();
    if (c != ':') {
        auto ctx = stream_->get_error_context("bad call");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    return _read_int_body();
}

int RESPStream::_read_string_body(Byte *buffer, size_t byte_buffer_size) {
    auto p = buffer;
    int quota = std::min(byte_buffer_size, (size_t)RESPStream::STRING_LENGTH_MAX);
    while(quota) {
        Byte c = stream_->get();
        if (c == '\r') {
            c = stream_->get();
            if (c == '\n') {
                return p - buffer;
            } else {
                auto ctx = stream_->get_error_context("bad end of sequence");
                BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
            }
        }
        *p++ = c;
        quota--;
    }
    auto ctx = stream_->get_error_context("out of quota");
    BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
}

int RESPStream::read_string(Byte *buffer, size_t byte_buffer_size) {
    Byte c = stream_->get();
    if (c != '+') {
        auto ctx = stream_->get_error_context("bad call");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    return _read_string_body(buffer, byte_buffer_size);
}

int RESPStream::read_bulkstr(Byte *buffer, size_t buffer_size) {
    Byte c = stream_->get();
    if (c != '$') {
        auto ctx = stream_->get_error_context("bad call");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    // parse "{value}\r\n"
    uint64_t n = _read_int_body();
    if (n > RESPStream::BULK_LENGTH_MAX) {
        auto ctx = stream_->get_error_context("declared object size is too large");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    if (n > buffer_size) {
        // buffer is too small
        auto ctx = stream_->get_error_context("declared object size is too large");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    int nread = stream_->read(buffer, n);
    if (nread < 0) {
        // stream error
        return nread;
    }
    Byte cr = stream_->get();
    Byte lf = stream_->get();
    if (cr != '\r' || lf != '\n') {
        auto ctx = stream_->get_error_context("bad end of stream");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    return nread;
}

uint64_t RESPStream::read_array_size() {
    Byte c = stream_->get();
    if (c != '*') {
        auto ctx = stream_->get_error_context("bad call");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    return _read_int_body();
}

}
<commit_msg>Both CRLF and LF line endingth supported by RESP implementation.<commit_after>#include "resp.h"
#include <boost/exception/all.hpp>
#include <cassert>

namespace Akumuli {

RESPError::RESPError(std::string msg, int pos)
    : StreamError(msg, pos)
{
}

RESPStream::RESPStream(ByteStreamReader *stream) {
    stream_ = stream;
}

RESPStream::Type RESPStream::next_type() const {
    auto ch = stream_->pick();
    Type result = BAD;
    switch(ch) {
    case '+':
        result = STRING;
        break;
    case ':':
        result = INTEGER;
        break;
    case '$':
        result = BULK_STR;
        break;
    case '*':
        result = ARRAY;
        break;
    case '-':
        result = ERROR;
        break;
    default:
        result = BAD;
        break;
    };
    return result;
}

uint64_t RESPStream::_read_int_body() {
    uint64_t result = 0;
    const int MAX_DIGITS = 84;  // Maximum number of decimal digits in uint64_t
    int quota = MAX_DIGITS;
    while(quota) {
        Byte c = stream_->get();
        if (c == '\n') {
            // Note: I decided to support both \r\n and \n line endings in Akumuli for simplicity.
            return result;
        } else if (c == '\r') {
            c = stream_->get();
            if (c == '\n') {
                return result;
            }
            // Bad stream
            auto ctx = stream_->get_error_context("invalid symbol inside stream - '\\r'");
            BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
        }
        // c must be in [0x30:0x39] range
        if (c > 0x39 || c < 0x30) {
            auto ctx = stream_->get_error_context("can't parse integer (character value out of range)");
            BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
        }
        result = result*10 + static_cast<int>(c & 0x0F);
        quota--;
    }
    auto ctx = stream_->get_error_context("integer is too long");
    BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
}

uint64_t RESPStream::read_int() {
    Byte c = stream_->get();
    if (c != ':') {
        auto ctx = stream_->get_error_context("bad call");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    return _read_int_body();
}

int RESPStream::_read_string_body(Byte *buffer, size_t byte_buffer_size) {
    auto p = buffer;
    int quota = std::min(byte_buffer_size, (size_t)RESPStream::STRING_LENGTH_MAX);
    while(quota) {
        Byte c = stream_->get();
        if (c == '\n') {
            return p - buffer;
        } else if (c == '\r') {
            c = stream_->get();
            if (c == '\n') {
                return p - buffer;
            } else {
                auto ctx = stream_->get_error_context("bad end of sequence");
                BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
            }
        }
        *p++ = c;
        quota--;
    }
    auto ctx = stream_->get_error_context("out of quota");
    BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
}

int RESPStream::read_string(Byte *buffer, size_t byte_buffer_size) {
    Byte c = stream_->get();
    if (c != '+') {
        auto ctx = stream_->get_error_context("bad call");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    return _read_string_body(buffer, byte_buffer_size);
}

int RESPStream::read_bulkstr(Byte *buffer, size_t buffer_size) {
    Byte c = stream_->get();
    if (c != '$') {
        auto ctx = stream_->get_error_context("bad call");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    // parse "{value}\r\n"
    uint64_t n = _read_int_body();
    if (n > RESPStream::BULK_LENGTH_MAX) {
        auto ctx = stream_->get_error_context("declared object size is too large");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    if (n > buffer_size) {
        // buffer is too small
        auto ctx = stream_->get_error_context("declared object size is too large");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    int nread = stream_->read(buffer, n);
    if (nread < 0) {
        // stream error
        return nread;
    }
    bool bad_eos = false;
    Byte cr = stream_->get();
    if (cr == '\r') {
        Byte lf = stream_->get();
        if (cr != '\r' || lf != '\n') {
            bad_eos = true;
        }
    } else if (cr != '\n') {
        bad_eos = true;
    }
    if (bad_eos) {
        auto ctx = stream_->get_error_context("bad end of stream");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    return nread;
}

uint64_t RESPStream::read_array_size() {
    Byte c = stream_->get();
    if (c != '*') {
        auto ctx = stream_->get_error_context("bad call");
        BOOST_THROW_EXCEPTION(RESPError(std::get<0>(ctx), std::get<1>(ctx)));
    }
    return _read_int_body();
}

}
<|endoftext|>