<commit_before>#define DEBUG2

//
// Created by Malachi Burke on 12/26/17.
//

#include "coap-dispatcher.h"

namespace moducom { namespace coap {

namespace experimental {

const char* get_description(OptionDecoder::State state)
{
    switch(state)
    {
        case OptionDecoder::OptionSize:
            return "Inspecting initial option data";

        case OptionDecoder::OptionDeltaDone:
            return "Delta (option number) found";

        case OptionDecoder::Payload:
            return "Payload marker found";

        case OptionDecoder::OptionDelta:
            return "Delta found";

        case OptionDecoder::OptionValue:
            return "Inspecting value data";

        case OptionDecoder::OptionValueDone:
            return "Value data complete";

        case OptionDecoder::OptionDeltaAndLengthDone:
            return "Delta and length simultaneously done";

        default:
            return NULLPTR;
    }
}

#ifdef DEBUG2
std::ostream& operator <<(std::ostream& out, OptionDecoder::State state)
{
    const char* description = get_description(state);

    if(description != NULLPTR)
        out << description;
    else
        out << (int)state;

    return out;
}
#endif

// TODO: Need a smooth way to ascertain end of CoAP message (remember multipart/streaming
// won't have a discrete message boundary)
bool Dispatcher::dispatch_iterate(Context& context)
{
    const pipeline::MemoryChunk& chunk = context.chunk;
    size_t& pos = context.pos; // how far into chunk our locus of processing should be
    bool process_done = false;

    switch(state())
    {
        case Uninitialized:
            // If necessary, initialize header decoder
            state(Header);
            init_header_decoder();
            break;

        case Header:
            while(pos < chunk.length && !process_done)
            {
                process_done = headerDecoder.process_iterate(chunk[pos]);

                // FIX: This meaning I believe is reversed from non decoder process calls
                // FIX: process_done does not designate whether bytes were consumed, for
                // headerDecoder and tokenDecoder, byte is always consumed
                pos++;
            }

            if(process_done) state(HeaderDone);

            break;

        case HeaderDone:
            dispatch_header();
            if(headerDecoder.token_length() > 0)
            {
                state(Token);
                // TODO: May want a TokenStart state
                init_token_decoder();
            }
            else
                state(OptionsStart);
            break;

        case Token:
            while(pos < chunk.length && !process_done)
            {
                // TODO: Utilize a simpler counter and chunk out token
                process_done = tokenDecoder.process_iterate(chunk[pos], headerDecoder.token_length());

                // FIX: This meaning I believe is reversed from non decoder process calls
                // FIX: process_done does not designate whether bytes were consumed, for
                // headerDecoder and tokenDecoder, byte is always consumed
                pos++;
            }

            if(process_done) state(TokenDone);

            break;

        case TokenDone:
            dispatch_token();

            state(OptionsStart);
            break;

        case OptionsStart:
            init_option_decoder();
            optionHolder.number_delta = 0;
            optionHolder.length = 0;
            state(Options);
            break;

        case Options:
        {
#ifdef DEBUG2
            std::clog << __func__ << ": 1 optionDecoder state = " << (optionDecoder.state()) << std::endl;
#endif

            pos += dispatch_option(chunk.remainder(pos));

#ifdef DEBUG2
            std::clog << __func__ << ": 2 optionDecoder state = " << (optionDecoder.state()) << std::endl;
#endif

            // handle option a.1), a.2) or b.1) described below
            if ((pos == chunk.length && context.last_chunk) || chunk[pos] == 0xFF)
            {
                ASSERT_ERROR(true,
                             (optionDecoder.state() == OptionDecoder::OptionValueDone) ||
                             (optionDecoder.state() == OptionDecoder::OptionDeltaAndLengthDone),
                             "Must be either optionValueDone or optionDeltaAndlengthDone.  Got: " << optionDecoder.state());
                // will check again for 0xFF
                state(OptionsDone);
            }
            else
            {
                // UNSUPPORTED
                // b.2 means we are not sure if another option or an incoming chunk[0] == 0xFF is coming
                // MAY need an OptionsBoundary state, but hopefully not
                // better would be to beef up OptionDecoder awareness of Payload marker
            }

            break;
        }

        case OptionsDone:
            // TODO: Need to peer into incoming data stream to determine if a payload is on the way
            // or not - specifically need to also check size.  Here there are 3 possibilities:
            //
            // a.1) payload marker present, so process a payload, entire chunk / datagram remainder present
            // a.2) payload marker present, but only partial chunk present, so more payload to process
            // b.1) end of datagram - entire chunk present
            // b.2) end of chunk - only partial chunk present
            // c) as-yet-to-be-determined streaming end of chunk marker
            if (pos == chunk.length && context.last_chunk)
            {
                // this is for condition b.1)
                state(Done);
            }
            else if (chunk[pos] == 0xFF)
            {
                pos++;

                // this is for condition a.1 or 1.2
                state(Payload);
            }
            else
            {
                // UNSUPPORTED
                // falls through to condition c, but could get a false positive on header 0xFF
                // so this is unsupported.  Plus we can't really get here properly from Options state
                state(Done);
            }
            break;

        case Payload:
        {
            bool last_payload_chunk = context.last_chunk;

            if(pos == 0)
                // arrives here in the unlikely case payload starts on new chunk
                // boundary
                dispatch_payload(chunk, last_payload_chunk);
            else
                // typically represents an a.1 scenario, but doesn't have to
                dispatch_payload(chunk.remainder(pos), last_payload_chunk);

            // pos not advanced since we expect caller to separate out streaming coap payload end from
            // next coap begin and create an artificial chunk boundary
            pos = chunk.length;
            state(PayloadDone);
            break;
        }

        case PayloadDone:
            //dispatch_payload(chunk, true);
            state(Done);
            break;

        case Done:
            state(Uninitialized);
            break;
    }

    // TODO: Do an assert to make sure pos never is >
    ASSERT_ERROR(true, pos <= chunk.length, "pos should never exceed chunk length");

    return pos == chunk.length;
}

void Dispatcher::dispatch_header()
{
    handler_t* handler = head();

    while(handler != NULLPTR)
    {
        handler->on_header(headerDecoder);
        handler = handler->next();
    }
}

// also handles pre-dispatch processing
// 100% untested
size_t Dispatcher::dispatch_option(const pipeline::MemoryChunk& optionChunk)
{
    // FIX: we generally expect to be at OptionSize state here, however in the future this
    // requirement should go away (once we clean up needs_value_processed behavior)
    size_t processed_length = optionDecoder.process_iterate(optionChunk, &optionHolder);
    size_t value_pos = processed_length;

    // FIX: Kludgey, can really be cleaned up and optimized
    // ensures that our linked list doesn't execute process_iterate multiple times to acquire
    // option-value.  Instead, our linked list looping might need to happen per state() switched on
    // Will also cause problems if there are no registered handlers, since count will be off as
    // value is never processed
    bool needs_value_processed = true;
    size_t total_length = processed_length;

    handler_t* handler = head();

    while(handler != NULLPTR)
    {
        if(handler->is_interested())
        {
            switch (optionDecoder.state())
            {
                case OptionDecoder::OptionLengthDone:
                case OptionDecoder::OptionDeltaAndLengthDone:
                {
                    handler->on_option((IOptionInput::number_t) optionHolder.number_delta, optionHolder.length);

                    if(needs_value_processed)
                    {
                        // Getting here
                        processed_length = optionDecoder.process_iterate(optionChunk.remainder(processed_length), &optionHolder);
                        total_length += processed_length;
                        needs_value_processed = false;
                    }

                    // TODO: Need to demarkate boundary here too so that on_option knows where boundary starts
                    pipeline::MemoryChunk partialChunk(optionChunk.data + value_pos, processed_length);

                    // FIX: We are arriving here with values of OptionSize(Done?) and OptionValue
                    // suggesting strongly we aren't iterating completely or fast-forwarding past
                    // value when we need to
                    bool full_option_value = optionDecoder.state() == OptionDecoder::OptionValueDone;
                    handler->on_option(partialChunk, full_option_value);
                    break;
                }

                case OptionDecoder::OptionSizeDone:

                    break;

                case OptionDecoder::OptionValue:
                {
                    // FIX: Not yet tested
                    //processed_length = optionDecoder.process_iterate(optionChunk, NULLPTR);
                    //pipeline::MemoryChunk partialChunk(optionChunk.data, processed_length);
                    //bool full_option_value = optionDecoder.state() == OptionDecoder::OptionValueDone;
                    //handler->on_option(partialChunk, full_option_value);
                    handler->on_option(optionChunk, false);
                    break;
                }

                case OptionDecoder::OptionValueDone:
                {
                    // FIX: Not yet supported
                    // FIX: Not quite correct code.  We need to suss out how large
                    // the chunk we're passing through really is and of course
                    // at what boundary it starts
                    //processed_length = optionDecoder.process_iterate(optionChunk, NULLPTR);
                    handler->on_option(optionChunk, true);
                    break;
                }

                case OptionDecoder::Payload:
                    // NOTE: Not yet used, we don't iterate enough to get here
                    break;

                default:break;
            }
        }

        handler = handler->next();
    }

    return total_length;
}

void Dispatcher::dispatch_payload(const pipeline::MemoryChunk& payloadChunk, bool last_chunk)
{
    //size_t processed_length = optionDecoder.process_iterate(payloadChunk, NULLPTR);

    handler_t* handler = head();

    while(handler != NULLPTR)
    {
        if(handler->is_interested())
        {
            handler->on_payload(payloadChunk, last_chunk);
        }

        handler = handler->next();
    }
}

void Dispatcher::dispatch_token()
{
    handler_t* handler = head();
    pipeline::MemoryChunk chunk(tokenDecoder.data(), headerDecoder.token_length());

    while(handler != NULLPTR)
    {
        if(handler->is_interested())
        {
            // this dispatcher does not chunk out token, we gather the whole thing in a local buffer
            // FIX: really though we SHOULD chunk it out (if necessary) and avoid allocating a buffer
            // entirely - under the right circumstances
            // for character-by-character scenarios though we DO prefer to have this mini-buffered
            // version.  As such, we probably want a separate dispatcher which is optimized for character
            // by character dispatching which uses this TokenDecoder
            handler->on_token(chunk, true);
        }

        handler = handler->next();
    }
}

}

}}
<commit_msg>Adding diagnostic logging for option receipt<commit_after>#define DEBUG2

//
// Created by Malachi Burke on 12/26/17.
//

#include "coap-dispatcher.h"

namespace moducom { namespace coap {

namespace experimental {

const char* get_description(OptionDecoder::State state)
{
    switch(state)
    {
        case OptionDecoder::OptionSize:
            return "Inspecting initial option data";

        case OptionDecoder::OptionDeltaDone:
            return "Delta (option number) found";

        case OptionDecoder::Payload:
            return "Payload marker found";

        case OptionDecoder::OptionDelta:
            return "Delta found";

        case OptionDecoder::OptionValue:
            return "Inspecting value data";

        case OptionDecoder::OptionValueDone:
            return "Value data complete";

        case OptionDecoder::OptionDeltaAndLengthDone:
            return "Delta and length simultaneously done";

        default:
            return NULLPTR;
    }
}

#ifdef DEBUG2
std::ostream& operator <<(std::ostream& out, OptionDecoder::State state)
{
    const char* description = get_description(state);

    if(description != NULLPTR)
        out << description;
    else
        out << (int)state;

    return out;
}
#endif

// TODO: Need a smooth way to ascertain end of CoAP message (remember multipart/streaming
// won't have a discrete message boundary)
bool Dispatcher::dispatch_iterate(Context& context)
{
    const pipeline::MemoryChunk& chunk = context.chunk;
    size_t& pos = context.pos; // how far into chunk our locus of processing should be
    bool process_done = false;

    switch(state())
    {
        case Uninitialized:
            // If necessary, initialize header decoder
            state(Header);
            init_header_decoder();
            break;

        case Header:
            while(pos < chunk.length && !process_done)
            {
                process_done = headerDecoder.process_iterate(chunk[pos]);

                // FIX: This meaning I believe is reversed from non decoder process calls
                // FIX: process_done does not designate whether bytes were consumed, for
                // headerDecoder and tokenDecoder, byte is always consumed
                pos++;
            }

            if(process_done) state(HeaderDone);

            break;

        case HeaderDone:
            dispatch_header();
            if(headerDecoder.token_length() > 0)
            {
                state(Token);
                // TODO: May want a TokenStart state
                init_token_decoder();
            }
            else
                state(OptionsStart);
            break;

        case Token:
            while(pos < chunk.length && !process_done)
            {
                // TODO: Utilize a simpler counter and chunk out token
                process_done = tokenDecoder.process_iterate(chunk[pos], headerDecoder.token_length());

                // FIX: This meaning I believe is reversed from non decoder process calls
                // FIX: process_done does not designate whether bytes were consumed, for
                // headerDecoder and tokenDecoder, byte is always consumed
                pos++;
            }

            if(process_done) state(TokenDone);

            break;

        case TokenDone:
            dispatch_token();

            state(OptionsStart);
            break;

        case OptionsStart:
            init_option_decoder();
            optionHolder.number_delta = 0;
            optionHolder.length = 0;
            state(Options);
            break;

        case Options:
        {
#ifdef DEBUG2
            std::clog << __func__ << ": 1 optionDecoder state = " << (optionDecoder.state()) << std::endl;
#endif

            pos += dispatch_option(chunk.remainder(pos));

#ifdef DEBUG2
            std::clog << __func__ << ": 2 optionDecoder state = " << (optionDecoder.state()) << std::endl;
#endif

            // handle option a.1), a.2) or b.1) described below
            if ((pos == chunk.length && context.last_chunk) || chunk[pos] == 0xFF)
            {
                ASSERT_ERROR(true,
                             (optionDecoder.state() == OptionDecoder::OptionValueDone) ||
                             (optionDecoder.state() == OptionDecoder::OptionDeltaAndLengthDone),
                             "Must be either optionValueDone or optionDeltaAndlengthDone.  Got: " << optionDecoder.state());
                // will check again for 0xFF
                state(OptionsDone);
            }
            else
            {
                // UNSUPPORTED
                // b.2 means we are not sure if another option or an incoming chunk[0] == 0xFF is coming
                // MAY need an OptionsBoundary state, but hopefully not
                // better would be to beef up OptionDecoder awareness of Payload marker
            }

            break;
        }

        case OptionsDone:
            // TODO: Need to peer into incoming data stream to determine if a payload is on the way
            // or not - specifically need to also check size.  Here there are 3 possibilities:
            //
            // a.1) payload marker present, so process a payload, entire chunk / datagram remainder present
            // a.2) payload marker present, but only partial chunk present, so more payload to process
            // b.1) end of datagram - entire chunk present
            // b.2) end of chunk - only partial chunk present
            // c) as-yet-to-be-determined streaming end of chunk marker
            if (pos == chunk.length && context.last_chunk)
            {
                // this is for condition b.1)
                state(Done);
            }
            else if (chunk[pos] == 0xFF)
            {
                pos++;

                // this is for condition a.1 or 1.2
                state(Payload);
            }
            else
            {
                // UNSUPPORTED
                // falls through to condition c, but could get a false positive on header 0xFF
                // so this is unsupported.  Plus we can't really get here properly from Options state
                state(Done);
            }
            break;

        case Payload:
        {
            bool last_payload_chunk = context.last_chunk;

            if(pos == 0)
                // arrives here in the unlikely case payload starts on new chunk
                // boundary
                dispatch_payload(chunk, last_payload_chunk);
            else
                // typically represents an a.1 scenario, but doesn't have to
                dispatch_payload(chunk.remainder(pos), last_payload_chunk);

            // pos not advanced since we expect caller to separate out streaming coap payload end from
            // next coap begin and create an artificial chunk boundary
            pos = chunk.length;
            state(PayloadDone);
            break;
        }

        case PayloadDone:
            //dispatch_payload(chunk, true);
            state(Done);
            break;

        case Done:
            state(Uninitialized);
            break;
    }

    // TODO: Do an assert to make sure pos never is >
    ASSERT_ERROR(true, pos <= chunk.length, "pos should never exceed chunk length");

    return pos == chunk.length;
}

void Dispatcher::dispatch_header()
{
    handler_t* handler = head();

    while(handler != NULLPTR)
    {
        handler->on_header(headerDecoder);
        handler = handler->next();
    }
}

// also handles pre-dispatch processing
// 100% untested
size_t Dispatcher::dispatch_option(const pipeline::MemoryChunk& optionChunk)
{
    // FIX: we generally expect to be at OptionSize state here, however in the future this
    // requirement should go away (once we clean up needs_value_processed behavior)
    size_t processed_length = optionDecoder.process_iterate(optionChunk, &optionHolder);
    size_t value_pos = processed_length;

    // FIX: Kludgey, can really be cleaned up and optimized
    // ensures that our linked list doesn't execute process_iterate multiple times to acquire
    // option-value.  Instead, our linked list looping might need to happen per state() switched on
    // Will also cause problems if there are no registered handlers, since count will be off as
    // value is never processed
    bool needs_value_processed = true;
    size_t total_length = processed_length;

    handler_t* handler = head();

    while(handler != NULLPTR)
    {
        if(handler->is_interested())
        {
            switch (optionDecoder.state())
            {
                case OptionDecoder::OptionLengthDone:
                case OptionDecoder::OptionDeltaAndLengthDone:
                {
                    IOptionInput::number_t option_number = (IOptionInput::number_t) optionHolder.number_delta;
                    uint16_t option_length = optionHolder.length;
#ifdef DEBUG2
                    std::clog << "Dispatching option: " << option_number << " with length " << optionHolder.length;
                    std::clog << std::endl;
#endif
                    handler->on_option(option_number, option_length);

                    if(needs_value_processed)
                    {
                        // Getting here
                        processed_length = optionDecoder.process_iterate(optionChunk.remainder(processed_length), &optionHolder);
                        total_length += processed_length;
                        needs_value_processed = false;
                    }

                    ASSERT_WARN(option_length, processed_length, "option length mismatch with processed bytes");

                    if(option_length > 0)
                    {
                        // TODO: Need to demarkate boundary here too so that on_option knows where boundary starts
                        pipeline::MemoryChunk partialChunk(optionChunk.data + value_pos, processed_length);

#ifdef DEBUG2
                        std::clog << "Dispatching option: data = ";

                        // once we resolve the two different OptionExperimentals, use this
                        //CoAP::OptionExperimental::get_format()
                        //optionHolder.get_format();
                        // for now, just assume everything is a string
                        for(int i = 0; i < option_length; i++)
                        {
                            std::clog << (char)partialChunk[i];
                        }

                        std::clog << std::endl;
#endif
                        // FIX: We are arriving here with values of OptionSize(Done?) and OptionValue
                        // suggesting strongly we aren't iterating completely or fast-forwarding past
                        // value when we need to
                        bool full_option_value = optionDecoder.state() == OptionDecoder::OptionValueDone;
                        handler->on_option(partialChunk, full_option_value);
                    }
                    break;
                }

                case OptionDecoder::OptionSizeDone:

                    break;

                case OptionDecoder::OptionValue:
                {
                    // FIX: Not yet tested
                    //processed_length = optionDecoder.process_iterate(optionChunk, NULLPTR);
                    //pipeline::MemoryChunk partialChunk(optionChunk.data, processed_length);
                    //bool full_option_value = optionDecoder.state() == OptionDecoder::OptionValueDone;
                    //handler->on_option(partialChunk, full_option_value);
                    handler->on_option(optionChunk, false);
                    break;
                }

                case OptionDecoder::OptionValueDone:
                {
                    // FIX: Not yet supported
                    // FIX: Not quite correct code.  We need to suss out how large
                    // the chunk we're passing through really is and of course
                    // at what boundary it starts
                    //processed_length = optionDecoder.process_iterate(optionChunk, NULLPTR);
                    handler->on_option(optionChunk, true);
                    break;
                }

                case OptionDecoder::Payload:
                    // NOTE: Not yet used, we don't iterate enough to get here
                    break;

                default:break;
            }
        }

        handler = handler->next();
    }

    return total_length;
}

void Dispatcher::dispatch_payload(const pipeline::MemoryChunk& payloadChunk, bool last_chunk)
{
    //size_t processed_length = optionDecoder.process_iterate(payloadChunk, NULLPTR);

    handler_t* handler = head();

    while(handler != NULLPTR)
    {
        if(handler->is_interested())
        {
            handler->on_payload(payloadChunk, last_chunk);
        }

        handler = handler->next();
    }
}

void Dispatcher::dispatch_token()
{
    handler_t* handler = head();
    pipeline::MemoryChunk chunk(tokenDecoder.data(), headerDecoder.token_length());

    while(handler != NULLPTR)
    {
        if(handler->is_interested())
        {
            // this dispatcher does not chunk out token, we gather the whole thing in a local buffer
            // FIX: really though we SHOULD chunk it out (if necessary) and avoid allocating a buffer
            // entirely - under the right circumstances
            // for character-by-character scenarios though we DO prefer to have this mini-buffered
            // version.  As such, we probably want a separate dispatcher which is optimized for character
            // by character dispatching which uses this TokenDecoder
            handler->on_token(chunk, true);
        }

        handler = handler->next();
    }
}

}

}}
<|endoftext|>


<commit_before>// cfiles, an analysis frontend for the Chemfiles library
// Copyright (C) 2015-2016 Guillaume Fraux
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

#include <docopt/docopt.h>
#include <sstream>
#include <fstream>

#include "HBonds.hpp"
#include "Errors.hpp"
#include "utils.hpp"
#include "geometry.hpp"

using namespace chemfiles;

static const double pi = 3.141592653589793238463;
static const char OPTIONS[] =
R"(Compute list of hydrogen bonds along a trajectory. Selections for the acceptor and donor atoms
can be specified using the chemfiles selection language. It is possible to provide an alternative
unit cell or topology for the trajectory file if they are not defined in the trajectory format.
Hydrogen bonds are defined as electrostatic attraction between two polar groups: the acceptor group
is a hydrogen atom covalently bound to an electronegative atom (usually O, N, F) while
the donor group is another highly electronegative atom.
The criteria used depend on a maximum donor-acceptor distance and a maximum donor-acceptor-H angle.
Hydrogen bonds criteria can be specified.

For more information about chemfiles selection language, please see
http://chemfiles.org/chemfiles/latest/selections.html

Usage:
  cfiles hbonds [options] <trajectory>
  cfiles hbonds (-h | --help)

Examples:
  cfiles hbonds water.xyz --cell 15:15:25 --guess-bonds
  cfiles hbonds in.pdb --acceptors=="bonds: type(#1) == O and type(#2) == H"
  cfiles hbonds protein.pdb --donors=="atoms: type N" -p 2.5:20.0

Options:
  -h --help                     show this help
  -o <file>, --output=<file>    write result to <file>. This default to the
                                trajectory file name with the `_hb.dat` extension.
  --format=<format>             force the input file format to be <format>
  -t <path>, --topology=<path>  alternative topology file for the input
  --topology-format=<format>    use <format> as format for the topology file
  --guess-bonds                 guess the bonds in the input
  -c <cell>, --cell=<cell>      alternative unit cell. <cell> format is one of
                                <a:b:c:α:β:γ> or <a:b:c> or <a>. 'a', 'b' and
                                'c' are in angstroms, 'α', 'β', and 'γ' are in
                                degrees.
  --steps=<steps>               steps to use from the input. <steps> format
                                is <start>:<end>[:<stride>] with <start>, <end>
                                and <stride> optional. Default is to use all
                                steps from the input; starting at 0, ending at
                                the last step, and with a stride of 1.
  --acceptors=<sel>             selection to use for the acceptors. This must be a
                                selection of size 2 and type bonds The second atom
				should be the hydrogen atom.
                                [default: bonds: type(#2) == H]
  --donors=<sel>                selection to use for the donors. This must be a
                                selection of size 1.
                                [default: atoms: type O or type N or type F]
  --distance=<dist>             distance criterion to use for the hydrogen bond detection.
                                'dist' is the donor-acceptor maximum distance in angstroms.
                                [default: 3.0]
  --angle=<angle>               angle criterion to use for the hydrogen bond detection.
                                'angle' is the donor-acceptor-hydrogen maximum angle in degrees.
                                [default: 30.0]
)";

static HBonds::Options parse_options(int argc, const char* argv[]) {
    auto options_str = command_header("hbonds", HBonds().description()) + "\n";
    options_str += "Laura Scalfi <laura.scalfi@ens.fr>\n";
    options_str += OPTIONS;
    auto args = docopt::docopt(options_str, {argv, argv + argc}, true, "");

    HBonds::Options options;
    options.trajectory = args.at("<trajectory>").asString();
    options.guess_bonds = args.at("--guess-bonds").asBool();

    options.selection_acceptor = args.at("--acceptors").asString();
    options.selection_donor = args.at("--donors").asString();

    if (args.at("--output")){
        options.outfile = args.at("--output").asString();
    } else {
        options.outfile = options.trajectory + "_hb.dat";
    }

    if (args.at("--steps")) {
        options.steps = steps_range::parse(args.at("--steps").asString());
    }

    if (args.at("--format")){
        options.format = args.at("--format").asString();
    }

    if (args.at("--topology")){
        if (options.guess_bonds) {
            throw CFilesError("Can not use both '--topology' and '--guess-bonds'");
        }
        options.topology = args.at("--topology").asString();
    }

    if (args.at("--topology-format")){
        if (options.topology == "") {
            throw CFilesError("Useless '--topology-format' without '--topology'");
        }
        options.topology_format = args.at("--topology-format").asString();
    }

    if (args.at("--cell")) {
        options.custom_cell = true;
        options.cell = parse_cell(args.at("--cell").asString());
	}

    options.distance = 3.0;
    options.angle = 30.0;
    if (args.at("--distance")) {
        try {
            options.distance = std::stod(args.at("--distance").asString());
        } catch(std::invalid_argument) {
            throw CFilesError("Invalid argument for distance criterion");
        }
    }
    if (args.at("--angle")) {
        try {
            options.angle = std::stod(args.at("--angle").asString())*pi/180;
        } catch(std::invalid_argument) {
            throw CFilesError("Invalid argument for angle criterion");
        }
    }

    return options;
}

std::string HBonds::description() const {
    return "compute hydrogen bonds network";
}

int HBonds::run(int argc, const char* argv[]) {
    auto options = parse_options(argc, argv);

    selection_acceptor_ = Selection(options.selection_acceptor);
    if (selection_acceptor_.size() != 2) {
        throw CFilesError("Can not use a selection for acceptors with size different than 2.");
    }

    auto selection_string = split(selection_acceptor_.string(),':');
    if (selection_string[0] != "bonds") {
        throw CFilesError("'Bonds' type selection compulsory for acceptors.");
    }

    selection_donor_ = Selection(options.selection_donor);
    if (selection_donor_.size() != 1) {
        throw CFilesError("Can not use a selection for donors with size larger than 1.");
    }

    auto infile = Trajectory(options.trajectory, 'r', options.format);
    std::ofstream outfile(options.outfile, std::ios::out);
    if (outfile.is_open()) {
        outfile << "#Hydrogen bond network in trajectory " << options.trajectory << std::endl;
        outfile << "# Selection: acceptors: " << options.selection_acceptor;
        outfile << " and donors: " << options.selection_donor << std::endl;
        outfile << "# Criteria:" << std::endl;
        outfile << "# donor-acceptor distance < " << options.distance << " angstroms" << std::endl;
        outfile << "# donor-acceptor-H angle < " << options.angle*180/pi << " degrees" << std::endl;
    } else {
        throw CFilesError("Could not open the '" + options.outfile + "' file.");
    }

    if (options.custom_cell) {
        infile.set_cell(options.cell);
    }

    if (options.topology != "") {
        infile.set_topology(options.topology, options.topology_format);
    }

    for (auto step: options.steps) {
        if (step >= infile.nsteps()) {
            break;
        }
        auto frame = infile.read_step(step);
        if (options.guess_bonds) {
            frame.guess_topology();
        }

        outfile << "# Frame: " << step << std::endl;

        auto positions = frame.positions();
        auto cell = frame.cell();

        auto matched = selection_acceptor_.evaluate(frame);
        for (auto match: matched) {
            assert(match.size() == 2);

            size_t acceptor = static_cast<size_t>(-1);
            size_t hydrogen = static_cast<size_t>(-1);

            if (frame.topology()[match[0]].type() == "H") {
                acceptor = match[1];
                hydrogen = match[0];
            }
            else if (frame.topology()[match[1]].type() == "H") {
                acceptor = match[0];
                hydrogen = match[1];
            }
            else
            {
                throw CFilesError("Invalid acceptors selection: there is no hydrogen atom.");
            }

            auto donors = selection_donor_.list(frame);
            for (auto donor: donors) {
                if (donor != acceptor && frame.topology()[donor].type() != "H") {
                    auto r_ad = cell.wrap(positions[donor] - positions[acceptor]);
                    auto distance = norm(r_ad);
                    auto r_ah = cell.wrap(positions[hydrogen] - positions[acceptor]);
                    auto theta = angle(r_ad, r_ah);
                    if (distance < options.distance && theta < options.angle) {
                        outfile << frame.topology()[donor].type() << donor << "   ";
                        outfile << frame.topology()[acceptor].type() << acceptor << "   ";
                        outfile << frame.topology()[hydrogen].type() << hydrogen << "  : ";
                        outfile << distance << "    ";
                        outfile << theta*180/pi << std::endl;
                    }
                }
            }
        }
    }

    return 0;
}
<commit_msg>Comment to explain output format<commit_after>// cfiles, an analysis frontend for the Chemfiles library
// Copyright (C) 2015-2016 Guillaume Fraux
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

#include <docopt/docopt.h>
#include <sstream>
#include <fstream>

#include "HBonds.hpp"
#include "Errors.hpp"
#include "utils.hpp"
#include "geometry.hpp"

using namespace chemfiles;

static const double pi = 3.141592653589793238463;
static const char OPTIONS[] =
R"(Compute list of hydrogen bonds along a trajectory. Selections for the acceptor and donor atoms
can be specified using the chemfiles selection language. It is possible to provide an alternative
unit cell or topology for the trajectory file if they are not defined in the trajectory format.
Hydrogen bonds are defined as electrostatic attraction between two polar groups: the acceptor group
is a hydrogen atom covalently bound to an electronegative atom (usually O, N, F) while
the donor group is another highly electronegative atom.
The criteria used depend on a maximum donor-acceptor distance and a maximum donor-acceptor-H angle.
Hydrogen bonds criteria can be specified.

For more information about chemfiles selection language, please see
http://chemfiles.org/chemfiles/latest/selections.html

Usage:
  cfiles hbonds [options] <trajectory>
  cfiles hbonds (-h | --help)

Examples:
  cfiles hbonds water.xyz --cell 15:15:25 --guess-bonds
  cfiles hbonds in.pdb --acceptors=="bonds: type(#1) == O and type(#2) == H"
  cfiles hbonds protein.pdb --donors=="atoms: type N" -p 2.5:20.0

Options:
  -h --help                     show this help
  -o <file>, --output=<file>    write result to <file>. This default to the
                                trajectory file name with the `_hb.dat` extension.
  --format=<format>             force the input file format to be <format>
  -t <path>, --topology=<path>  alternative topology file for the input
  --topology-format=<format>    use <format> as format for the topology file
  --guess-bonds                 guess the bonds in the input
  -c <cell>, --cell=<cell>      alternative unit cell. <cell> format is one of
                                <a:b:c:α:β:γ> or <a:b:c> or <a>. 'a', 'b' and
                                'c' are in angstroms, 'α', 'β', and 'γ' are in
                                degrees.
  --steps=<steps>               steps to use from the input. <steps> format
                                is <start>:<end>[:<stride>] with <start>, <end>
                                and <stride> optional. Default is to use all
                                steps from the input; starting at 0, ending at
                                the last step, and with a stride of 1.
  --acceptors=<sel>             selection to use for the acceptors. This must be a
                                selection of size 2 and type bonds The second atom
				should be the hydrogen atom.
                                [default: bonds: type(#2) == H]
  --donors=<sel>                selection to use for the donors. This must be a
                                selection of size 1.
                                [default: atoms: type O or type N or type F]
  --distance=<dist>             distance criterion to use for the hydrogen bond detection.
                                'dist' is the donor-acceptor maximum distance in angstroms.
                                [default: 3.0]
  --angle=<angle>               angle criterion to use for the hydrogen bond detection.
                                'angle' is the donor-acceptor-hydrogen maximum angle in degrees.
                                [default: 30.0]
)";

static HBonds::Options parse_options(int argc, const char* argv[]) {
    auto options_str = command_header("hbonds", HBonds().description()) + "\n";
    options_str += "Laura Scalfi <laura.scalfi@ens.fr>\n";
    options_str += OPTIONS;
    auto args = docopt::docopt(options_str, {argv, argv + argc}, true, "");

    HBonds::Options options;
    options.trajectory = args.at("<trajectory>").asString();
    options.guess_bonds = args.at("--guess-bonds").asBool();

    options.selection_acceptor = args.at("--acceptors").asString();
    options.selection_donor = args.at("--donors").asString();

    if (args.at("--output")){
        options.outfile = args.at("--output").asString();
    } else {
        options.outfile = options.trajectory + "_hb.dat";
    }

    if (args.at("--steps")) {
        options.steps = steps_range::parse(args.at("--steps").asString());
    }

    if (args.at("--format")){
        options.format = args.at("--format").asString();
    }

    if (args.at("--topology")){
        if (options.guess_bonds) {
            throw CFilesError("Can not use both '--topology' and '--guess-bonds'");
        }
        options.topology = args.at("--topology").asString();
    }

    if (args.at("--topology-format")){
        if (options.topology == "") {
            throw CFilesError("Useless '--topology-format' without '--topology'");
        }
        options.topology_format = args.at("--topology-format").asString();
    }

    if (args.at("--cell")) {
        options.custom_cell = true;
        options.cell = parse_cell(args.at("--cell").asString());
	}

    options.distance = 3.0;
    options.angle = 30.0;
    if (args.at("--distance")) {
        try {
            options.distance = std::stod(args.at("--distance").asString());
        } catch(std::invalid_argument) {
            throw CFilesError("Invalid argument for distance criterion");
        }
    }
    if (args.at("--angle")) {
        try {
            options.angle = std::stod(args.at("--angle").asString())*pi/180;
        } catch(std::invalid_argument) {
            throw CFilesError("Invalid argument for angle criterion");
        }
    }

    return options;
}

std::string HBonds::description() const {
    return "compute hydrogen bonds network";
}

int HBonds::run(int argc, const char* argv[]) {
    auto options = parse_options(argc, argv);

    selection_acceptor_ = Selection(options.selection_acceptor);
    if (selection_acceptor_.size() != 2) {
        throw CFilesError("Can not use a selection for acceptors with size different than 2.");
    }

    auto selection_string = split(selection_acceptor_.string(),':');
    if (selection_string[0] != "bonds") {
        throw CFilesError("'Bonds' type selection compulsory for acceptors.");
    }

    selection_donor_ = Selection(options.selection_donor);
    if (selection_donor_.size() != 1) {
        throw CFilesError("Can not use a selection for donors with size larger than 1.");
    }

    auto infile = Trajectory(options.trajectory, 'r', options.format);
    std::ofstream outfile(options.outfile, std::ios::out);
    if (outfile.is_open()) {
        outfile << "#Hydrogen bond network in trajectory " << options.trajectory << std::endl;
        outfile << "# Selection: acceptors: " << options.selection_acceptor;
        outfile << " and donors: " << options.selection_donor << std::endl;
        outfile << "# Criteria:" << std::endl;
        outfile << "# donor-acceptor distance < " << options.distance << " angstroms" << std::endl;
        outfile << "# donor-acceptor-H angle < " << options.angle*180/pi << " degrees" << std::endl;
    } else {
        throw CFilesError("Could not open the '" + options.outfile + "' file.");
    }

    if (options.custom_cell) {
        infile.set_cell(options.cell);
    }

    if (options.topology != "") {
        infile.set_topology(options.topology, options.topology_format);
    }

    for (auto step: options.steps) {
        if (step >= infile.nsteps()) {
            break;
        }
        auto frame = infile.read_step(step);
        if (options.guess_bonds) {
            frame.guess_topology();
        }

        outfile << "# Frame: " << step << std::endl;
        outfile << "# Donor   Acceptor   Hydrogen  : Distance D-A    Angle D-A-H" << std::endl;

        auto positions = frame.positions();
        auto cell = frame.cell();

        auto matched = selection_acceptor_.evaluate(frame);
        for (auto match: matched) {
            assert(match.size() == 2);

            size_t acceptor = static_cast<size_t>(-1);
            size_t hydrogen = static_cast<size_t>(-1);

            if (frame.topology()[match[0]].type() == "H") {
                acceptor = match[1];
                hydrogen = match[0];
            }
            else if (frame.topology()[match[1]].type() == "H") {
                acceptor = match[0];
                hydrogen = match[1];
            }
            else
            {
                throw CFilesError("Invalid acceptors selection: there is no hydrogen atom.");
            }

            auto donors = selection_donor_.list(frame);
            for (auto donor: donors) {
                if (donor != acceptor && frame.topology()[donor].type() != "H") {
                    auto r_ad = cell.wrap(positions[donor] - positions[acceptor]);
                    auto distance = norm(r_ad);
                    auto r_ah = cell.wrap(positions[hydrogen] - positions[acceptor]);
                    auto theta = angle(r_ad, r_ah);
                    if (distance < options.distance && theta < options.angle) {
                        outfile << frame.topology()[donor].type() << donor << "   ";
                        outfile << frame.topology()[acceptor].type() << acceptor << "   ";
                        outfile << frame.topology()[hydrogen].type() << hydrogen << "  : ";
                        outfile << distance << "    ";
                        outfile << theta*180/pi << std::endl;
                    }
                }
            }
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/************************************************************/
/*    NAME: Mike Bogochow, Jeff Masucci, Cody Noel          */
/*    ORGN: UNH                                             */
/*    FILE: ARDUINOComm.h                                   */
/*    DATE: March 2014                                      */
/************************************************************/
/* This is an implementation of IMOOSComm for communicating */
/* with an Arduino.                                         */
/************************************************************/

#include "ArduinoComm.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sstream>
#include <string.h>

#include <termios.h>

using namespace std;

ArduinoComm::ArduinoComm(const char *portName, int baudRate,
  const char *delimiter)
  : serialPortName(portName)
  , baudRate(baudRate)
  , delim(delimiter)
{
}

ArduinoComm::~ArduinoComm()
{
  close(serialFD);
}

/**
 * Open serial port with Arduino.
 * Based on arduino-serial.c by todbot
 * (https://github.com/todbot/arduino-serial)
 *
 * @return true on successful open of the serial port
 *         false if opening the serial port or getting/setting attributes failed
 */
bool ArduinoComm::openComm()
{
  struct termios options;
  speed_t baud = baudRate;

  serialFD = open(serialPortName, O_RDWR | O_NONBLOCK);
  if (serialFD < 0)
  {
    //MOOSTrace("Error opening serial (%s): %s\n", serialPortName,
    //  strerror(errno));
    return false;
  }

  if (tcgetattr(serialFD, &options) < 0)
  {
    //MOOSTrace("Failed to get terminal settings: %s\n", strerror(errno));
    return false;
  }

  switch (baudRate)
  {
    case 4800:   baud=B4800;   break;
    case 9600:   baud=B9600;   break;
#ifdef B14400
    case 14400:  baud=B14400;  break;
#endif
    case 19200:  baud=B19200;  break;
#ifdef B28800
    case 28800:  baud=B28800;  break;
#endif
    case 38400:  baud=B38400;  break;
    case 57600:  baud=B57600;  break;
    case 115200: baud=B115200; break;
  }

  cfsetispeed(&options, baud);
  cfsetospeed(&options, baud);

  // 8N1
  options.c_cflag &= ~PARENB;
  options.c_cflag &= ~CSTOPB;
  options.c_cflag &= ~CSIZE;
  options.c_cflag |= CS8;
  options.c_cflag &= ~CRTSCTS;  // no flow control
  //toptions.c_cflag &= ~HUPCL; // disable hang-up-on-close to avoid reset
  options.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
  options.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
  options.c_oflag &= ~OPOST; // make raw
  options.c_cc[VMIN]  = 0;
  options.c_cc[VTIME] = 0;
  //toptions.c_cc[VTIME] = 20;

  tcsetattr(serialFD, TCSANOW, &options);
  if (tcsetattr(serialFD, TCSAFLUSH, &options) < 0)
  {
    //MOOSTrace("Failed to set terminal settings: %s\n", strerror(errno));
    return false;
  }

  return true;
}

bool ArduinoComm::writeMsg(const char *name, double value)
{
  ostringstream ss;
  ss << value;
  return writeMsg(name, ss.str().c_str());
}

bool ArduinoComm::writeMsg(const char *name, const char *value)
{
  ostringstream ss;
  ss << name << '=' << value << delim;

  const char *msg = ss.str().c_str(); // Full message to sendi
  size_t msgLen = strlen(msg);        // Length of message we are sending
  ssize_t nBytes;                     // Actual number of bytes written

  // Check if we can write, return if not since we don't want to block
/*  struct pollfd mpollfd = { .fd = fd, .events = POLLOUT };
  MOOSTrace("POLL: %i\n", poll(&mpollfd, 1, 0));
  if (!(poll(&mpollfd, 1, 0) > 0))
    return MOOSFail("Stream is not ready for writing");*/

  // Write to our FIFO
  nBytes = write(serialFD, msg, msgLen);
  if (nBytes < 0)
    return false; // "Error writing to frontseat"

  return true;
}

int ArduinoComm::readMsg(char *buffer, int bufferLen)
{
  return read(serialFD, buffer, bufferLen);
}
<commit_msg>Added disabling hang up on close to stop resetting Arduino<commit_after>/************************************************************/
/*    NAME: Mike Bogochow, Jeff Masucci, Cody Noel          */
/*    ORGN: UNH                                             */
/*    FILE: ARDUINOComm.h                                   */
/*    DATE: March 2014                                      */
/************************************************************/
/* This is an implementation of IMOOSComm for communicating */
/* with an Arduino.                                         */
/************************************************************/

#include "ArduinoComm.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sstream>
#include <string.h>

#include <termios.h>

using namespace std;

ArduinoComm::ArduinoComm(const char *portName, int baudRate,
  const char *delimiter)
  : serialPortName(portName)
  , baudRate(baudRate)
  , delim(delimiter)
{
}

ArduinoComm::~ArduinoComm()
{
  close(serialFD);
}

/**
 * Open serial port with Arduino.
 * Based on arduino-serial.c by todbot
 * (https://github.com/todbot/arduino-serial)
 *
 * @return true on successful open of the serial port
 *         false if opening the serial port or getting/setting attributes failed
 */
bool ArduinoComm::openComm()
{
  struct termios options;
  speed_t baud = baudRate;

  serialFD = open(serialPortName, O_RDWR | O_NONBLOCK);
  if (serialFD < 0)
  {
    //MOOSTrace("Error opening serial (%s): %s\n", serialPortName,
    //  strerror(errno));
    return false;
  }

  if (tcgetattr(serialFD, &options) < 0)
  {
    //MOOSTrace("Failed to get terminal settings: %s\n", strerror(errno));
    return false;
  }

  switch (baudRate)
  {
    case 4800:   baud=B4800;   break;
    case 9600:   baud=B9600;   break;
#ifdef B14400
    case 14400:  baud=B14400;  break;
#endif
    case 19200:  baud=B19200;  break;
#ifdef B28800
    case 28800:  baud=B28800;  break;
#endif
    case 38400:  baud=B38400;  break;
    case 57600:  baud=B57600;  break;
    case 115200: baud=B115200; break;
  }

  cfsetispeed(&options, baud);
  cfsetospeed(&options, baud);

  // 8N1
  options.c_cflag &= ~PARENB;
  options.c_cflag &= ~CSTOPB;
  options.c_cflag &= ~CSIZE;
  options.c_cflag |= CS8;
  options.c_cflag &= ~CRTSCTS;  // no flow control
  options.c_cflag |= CREAD | CLOCAL;  // turn on READ & ignore ctrl lines
  options.c_cflag &= ~HUPCL; // disable hang-up-on-close to avoid reset
  options.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
  options.c_oflag &= ~OPOST; // make raw
  options.c_cc[VMIN]  = 0;
  options.c_cc[VTIME] = 0;
  //toptions.c_cc[VTIME] = 20;

  tcsetattr(serialFD, TCSANOW, &options);
  if (tcsetattr(serialFD, TCSAFLUSH, &options) < 0)
  {
    //MOOSTrace("Failed to set terminal settings: %s\n", strerror(errno));
    return false;
  }

  return true;
}

bool ArduinoComm::writeMsg(const char *name, double value)
{
  ostringstream ss;
  ss << value;
  return writeMsg(name, ss.str().c_str());
}

bool ArduinoComm::writeMsg(const char *name, const char *value)
{
  ostringstream ss;
  ss << name << '=' << value << delim;

  const char *msg = ss.str().c_str(); // Full message to sendi
  size_t msgLen = strlen(msg);        // Length of message we are sending
  ssize_t nBytes;                     // Actual number of bytes written

  // Check if we can write, return if not since we don't want to block
/*  struct pollfd mpollfd = { .fd = fd, .events = POLLOUT };
  MOOSTrace("POLL: %i\n", poll(&mpollfd, 1, 0));
  if (!(poll(&mpollfd, 1, 0) > 0))
    return MOOSFail("Stream is not ready for writing");*/

  // Write to our FIFO
  nBytes = write(serialFD, msg, msgLen);
  if (nBytes < 0)
    return false; // "Error writing to frontseat"

  return true;
}

int ArduinoComm::readMsg(char *buffer, int bufferLen)
{
  return read(serialFD, buffer, bufferLen);
}
<|endoftext|>


<commit_before>/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

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

    QGROUNDCONTROL 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.

    You should have received a copy of the GNU General Public License
    along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Implementation of SerialConfigurationWindow
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QDebug>

#include <SerialConfigurationWindow.h>
#include <SerialLinkInterface.h>
#include <QDir>
#include <QSettings>
#include <QFileInfoList>

SerialConfigurationWindow::SerialConfigurationWindow(LinkInterface* link, QWidget *parent, Qt::WindowFlags flags) : QWidget(parent, flags),
    userConfigured(false)
{
    SerialLinkInterface* serialLink = dynamic_cast<SerialLinkInterface*>(link);

    if(serialLink != 0)
    {
        serialLink->loadSettings();
        this->link = serialLink;

        // Setup the user interface according to link type
        ui.setupUi(this);

        // Create action to open this menu
        // Create configuration action for this link
        // Connect the current UAS
        action = new QAction(QIcon(":/images/devices/network-wireless.svg"), "", link);
        setLinkName(link->getName());

        setupPortList();

        // Set up baud rates
        ui.baudRate->clear();
        ui.baudRate->addItem("50", 50);
        ui.baudRate->addItem("70", 70);
        ui.baudRate->addItem("110", 110);
        ui.baudRate->addItem("134", 134);
        ui.baudRate->addItem("150", 150);
        ui.baudRate->addItem("200", 200);
        ui.baudRate->addItem("300", 300);
        ui.baudRate->addItem("600", 600);
        ui.baudRate->addItem("1200", 1200);
        ui.baudRate->addItem("1800", 1800);
        ui.baudRate->addItem("2400", 2400);
        ui.baudRate->addItem("4800", 4800);
        ui.baudRate->addItem("9600", 9600);
#ifdef Q_OS_WIN
        ui.baudRate->addItem("14400", 14400);
#endif
        ui.baudRate->addItem("19200", 19200);
        ui.baudRate->addItem("38400", 38400);
#ifdef Q_OS_WIN
        ui.baudRate->addItem("56000", 56000);
#endif
        ui.baudRate->addItem("57600", 57600);
#ifdef Q_OS_WIN
        ui.baudRate->addItem("76800", 76800);
#endif
        ui.baudRate->addItem("115200", 115200);
#ifdef Q_OS_WIN
        ui.baudRate->addItem("128000", 128000);
        ui.baudRate->addItem("230400", 230400);
        ui.baudRate->addItem("256000", 256000);
        ui.baudRate->addItem("460800", 460800);
#endif
        ui.baudRate->addItem("921600", 921600);

        connect(action, SIGNAL(triggered()), this, SLOT(configureCommunication()));

        // Make sure that a change in the link name will be reflected in the UI
        connect(link, SIGNAL(nameChanged(QString)), this, SLOT(setLinkName(QString)));

        // Connect the individual user interface inputs
        connect(ui.portName, SIGNAL(editTextChanged(QString)), this, SLOT(setPortName(QString)));
        connect(ui.portName, SIGNAL(currentIndexChanged(QString)), this, SLOT(setPortName(QString)));
        connect(ui.baudRate, SIGNAL(activated(QString)), this->link, SLOT(setBaudRateString(QString)));
        connect(ui.flowControlCheckBox, SIGNAL(toggled(bool)), this, SLOT(enableFlowControl(bool)));
        connect(ui.parNone, SIGNAL(toggled(bool)), this, SLOT(setParityNone(bool)));
        connect(ui.parOdd, SIGNAL(toggled(bool)), this, SLOT(setParityOdd(bool)));
        connect(ui.parEven, SIGNAL(toggled(bool)), this, SLOT(setParityEven(bool)));
        connect(ui.dataBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setDataBits(int)));
        connect(ui.stopBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setStopBits(int)));

        //connect(this->link, SIGNAL(connected(bool)), this, SLOT());
        ui.portName->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
        ui.baudRate->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);

        switch(this->link->getParityType()) {
        case 0:
            ui.parNone->setChecked(true);
            break;
        case 1:
            ui.parOdd->setChecked(true);
            break;
        case 2:
            ui.parEven->setChecked(true);
            break;
        default:
            // Enforce default: no parity in link
            setParityNone(true);
            ui.parNone->setChecked(true);
            break;
        }

        switch(this->link->getFlowType()) {
        case 0:
            ui.flowControlCheckBox->setChecked(false);
            break;
        case 1:
            ui.flowControlCheckBox->setChecked(true);
            break;
        default:
            ui.flowControlCheckBox->setChecked(false);
            enableFlowControl(false);
        }

        ui.baudRate->setCurrentIndex(ui.baudRate->findText(QString("%1").arg(this->link->getBaudRate())));

        ui.dataBitsSpinBox->setValue(this->link->getDataBits());
        ui.stopBitsSpinBox->setValue(this->link->getStopBits());

        portCheckTimer = new QTimer(this);
        portCheckTimer->setInterval(1000);
        connect(portCheckTimer, SIGNAL(timeout()), this, SLOT(setupPortList()));

        // Display the widget
        this->window()->setWindowTitle(tr("Serial Communication Settings"));
    }
    else
    {
        qDebug() << "Link is NOT a serial link, can't open configuration window";
    }
}

SerialConfigurationWindow::~SerialConfigurationWindow()
{

}

void SerialConfigurationWindow::showEvent(QShowEvent* event)
{
    Q_UNUSED(event);
    portCheckTimer->start();
}

void SerialConfigurationWindow::hideEvent(QHideEvent* event)
{
    Q_UNUSED(event);
    portCheckTimer->stop();
}

QAction* SerialConfigurationWindow::getAction()
{
    return action;
}

void SerialConfigurationWindow::configureCommunication()
{
    QString selected = ui.portName->currentText();
    setupPortList();
    ui.portName->setEditText(selected);
    this->show();
}

void SerialConfigurationWindow::setupPortList()
{
    if (!link) return;

    if (!userConfigured)
    {
        ui.portName->clear();
        ui.portName->clearEditText();
    }
    // Get the ports available on this system
    QVector<QString>* ports = link->getCurrentPorts();

    // Add the ports in reverse order, because we prepend them to the list
    for (int i = ports->size() - 1; i >= 0; --i)
    {
        // Prepend newly found port to the list
        if (ui.portName->findText(ports->at(i)) == -1)
        {
            ui.portName->insertItem(0, ports->at(i));
            if (!userConfigured) ui.portName->setEditText(ports->at(i));
        }
    }

    ui.portName->setEditText(this->link->getPortName());
}

void SerialConfigurationWindow::enableFlowControl(bool flow)
{
    if(flow)
    {
        link->setFlowType(1);
    }
    else
    {
        link->setFlowType(0);
    }
}

void SerialConfigurationWindow::setParityNone(bool accept)
{
    if (accept) link->setParityType(0);
}

void SerialConfigurationWindow::setParityOdd(bool accept)
{
    if (accept) link->setParityType(1);
}

void SerialConfigurationWindow::setParityEven(bool accept)
{
    if (accept) link->setParityType(2);
}

void SerialConfigurationWindow::setPortName(QString port)
{
#ifdef Q_OS_WIN
    port = port.split("-").first();
#endif
    port = port.remove(" ");

    if (this->link->getPortName() != port) {
        link->setPortName(port);
    }
    userConfigured = true;
}

void SerialConfigurationWindow::setLinkName(QString name)
{
    Q_UNUSED(name);
    // FIXME
    action->setText(tr("Configure ") + link->getName());
    action->setStatusTip(tr("Configure ") + link->getName());
    setWindowTitle(tr("Configuration of ") + link->getName());
}

<commit_msg>Match the listed supported serial ports in the UI to those supported by QSerialPort. This commit unifies the supported baud rates completely across QGC and OSes.<commit_after>/*=====================================================================

QGroundControl Open Source Ground Control Station

(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

This file is part of the QGROUNDCONTROL project

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

    QGROUNDCONTROL 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.

    You should have received a copy of the GNU General Public License
    along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

======================================================================*/

/**
 * @file
 *   @brief Implementation of SerialConfigurationWindow
 *   @author Lorenz Meier <mavteam@student.ethz.ch>
 *
 */

#include <QDebug>

#include <SerialConfigurationWindow.h>
#include <SerialLinkInterface.h>
#include <QDir>
#include <QSettings>
#include <QFileInfoList>

SerialConfigurationWindow::SerialConfigurationWindow(LinkInterface* link, QWidget *parent, Qt::WindowFlags flags) : QWidget(parent, flags),
    userConfigured(false)
{
    SerialLinkInterface* serialLink = dynamic_cast<SerialLinkInterface*>(link);

    if(serialLink != 0)
    {
        serialLink->loadSettings();
        this->link = serialLink;

        // Setup the user interface according to link type
        ui.setupUi(this);

        // Create action to open this menu
        // Create configuration action for this link
        // Connect the current UAS
        action = new QAction(QIcon(":/images/devices/network-wireless.svg"), "", link);
        setLinkName(link->getName());

        setupPortList();

        // Set up baud rates
        ui.baudRate->clear();

		// Keep track of all desired baud rates by OS. These are iterated through
		// later and added to ui.baudRate.
		QList<int> supportedBaudRates;

		// Baud rates supported only by POSIX systems
#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_DARWIN)
		supportedBaudRates << 50;
		supportedBaudRates << 75;
		supportedBaudRates << 134;
		supportedBaudRates << 150;
		supportedBaudRates << 200;
		supportedBaudRates << 1800;
#endif
		// Baud rates supported only by Linux
#if defined(Q_OS_LINUX)
		supportedBaudRates << 230400;
		supportedBaudRates << 460800;
		supportedBaudRates << 500000;
		supportedBaudRates << 576000;
		supportedBaudRates << 921600;
#endif

		// Baud rates supported only by Windows
#if defined(Q_OS_WIN)
		supportedBaudRates << 14400;
		supportedBaudRates << 56000;
		supportedBaudRates << 128000;
		supportedBaudRates << 256000;
#endif

		// Baud rates supported by everyone
		supportedBaudRates << 110;
		supportedBaudRates << 300;
		supportedBaudRates << 600;
		supportedBaudRates << 1200;
		supportedBaudRates << 2400;
		supportedBaudRates << 4800;
		supportedBaudRates << 9600;
		supportedBaudRates << 19200;
		supportedBaudRates << 38400;
		supportedBaudRates << 57600;
		supportedBaudRates << 115200;

		// Now actually add all of our supported baud rates to the UI.
		qSort(supportedBaudRates.begin(), supportedBaudRates.end());
		for (int i = 0; i < supportedBaudRates.size(); ++i) {
			ui.baudRate->addItem(QString::number(supportedBaudRates.at(i)), supportedBaudRates.at(i));
		}

        connect(action, SIGNAL(triggered()), this, SLOT(configureCommunication()));

        // Make sure that a change in the link name will be reflected in the UI
        connect(link, SIGNAL(nameChanged(QString)), this, SLOT(setLinkName(QString)));

        // Connect the individual user interface inputs
        connect(ui.portName, SIGNAL(editTextChanged(QString)), this, SLOT(setPortName(QString)));
        connect(ui.portName, SIGNAL(currentIndexChanged(QString)), this, SLOT(setPortName(QString)));
        connect(ui.baudRate, SIGNAL(activated(QString)), this->link, SLOT(setBaudRateString(QString)));
        connect(ui.flowControlCheckBox, SIGNAL(toggled(bool)), this, SLOT(enableFlowControl(bool)));
        connect(ui.parNone, SIGNAL(toggled(bool)), this, SLOT(setParityNone(bool)));
        connect(ui.parOdd, SIGNAL(toggled(bool)), this, SLOT(setParityOdd(bool)));
        connect(ui.parEven, SIGNAL(toggled(bool)), this, SLOT(setParityEven(bool)));
        connect(ui.dataBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setDataBits(int)));
        connect(ui.stopBitsSpinBox, SIGNAL(valueChanged(int)), this->link, SLOT(setStopBits(int)));

        //connect(this->link, SIGNAL(connected(bool)), this, SLOT());
        ui.portName->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
        ui.baudRate->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);

        switch(this->link->getParityType()) {
        case 0:
            ui.parNone->setChecked(true);
            break;
        case 1:
            ui.parOdd->setChecked(true);
            break;
        case 2:
            ui.parEven->setChecked(true);
            break;
        default:
            // Enforce default: no parity in link
            setParityNone(true);
            ui.parNone->setChecked(true);
            break;
        }

        switch(this->link->getFlowType()) {
        case 0:
            ui.flowControlCheckBox->setChecked(false);
            break;
        case 1:
            ui.flowControlCheckBox->setChecked(true);
            break;
        default:
            ui.flowControlCheckBox->setChecked(false);
            enableFlowControl(false);
        }

        ui.baudRate->setCurrentIndex(ui.baudRate->findText(QString("%1").arg(this->link->getBaudRate())));

        ui.dataBitsSpinBox->setValue(this->link->getDataBits());
        ui.stopBitsSpinBox->setValue(this->link->getStopBits());

        portCheckTimer = new QTimer(this);
        portCheckTimer->setInterval(1000);
        connect(portCheckTimer, SIGNAL(timeout()), this, SLOT(setupPortList()));

        // Display the widget
        this->window()->setWindowTitle(tr("Serial Communication Settings"));
    }
    else
    {
        qDebug() << "Link is NOT a serial link, can't open configuration window";
    }
}

SerialConfigurationWindow::~SerialConfigurationWindow()
{

}

void SerialConfigurationWindow::showEvent(QShowEvent* event)
{
    Q_UNUSED(event);
    portCheckTimer->start();
}

void SerialConfigurationWindow::hideEvent(QHideEvent* event)
{
    Q_UNUSED(event);
    portCheckTimer->stop();
}

QAction* SerialConfigurationWindow::getAction()
{
    return action;
}

void SerialConfigurationWindow::configureCommunication()
{
    QString selected = ui.portName->currentText();
    setupPortList();
    ui.portName->setEditText(selected);
    this->show();
}

void SerialConfigurationWindow::setupPortList()
{
    if (!link) return;

    if (!userConfigured)
    {
        ui.portName->clear();
        ui.portName->clearEditText();
    }
    // Get the ports available on this system
    QVector<QString>* ports = link->getCurrentPorts();

    // Add the ports in reverse order, because we prepend them to the list
    for (int i = ports->size() - 1; i >= 0; --i)
    {
        // Prepend newly found port to the list
        if (ui.portName->findText(ports->at(i)) == -1)
        {
            ui.portName->insertItem(0, ports->at(i));
            if (!userConfigured) ui.portName->setEditText(ports->at(i));
        }
    }

    ui.portName->setEditText(this->link->getPortName());
}

void SerialConfigurationWindow::enableFlowControl(bool flow)
{
    if(flow)
    {
        link->setFlowType(1);
    }
    else
    {
        link->setFlowType(0);
    }
}

void SerialConfigurationWindow::setParityNone(bool accept)
{
    if (accept) link->setParityType(0);
}

void SerialConfigurationWindow::setParityOdd(bool accept)
{
    if (accept) link->setParityType(1);
}

void SerialConfigurationWindow::setParityEven(bool accept)
{
    if (accept) link->setParityType(2);
}

void SerialConfigurationWindow::setPortName(QString port)
{
#ifdef Q_OS_WIN
    port = port.split("-").first();
#endif
    port = port.remove(" ");

    if (this->link->getPortName() != port) {
        link->setPortName(port);
    }
    userConfigured = true;
}

void SerialConfigurationWindow::setLinkName(QString name)
{
    Q_UNUSED(name);
    // FIXME
    action->setText(tr("Configure ") + link->getName());
    action->setStatusTip(tr("Configure ") + link->getName());
    setWindowTitle(tr("Configuration of ") + link->getName());
}

<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <Windows.h>
#include "kybrdCtrl.h"
#include "WearableDevice.h"
#include <vector>
#include <thread>

using namespace std;

#define KEYBOARD_CONTROL_TEST

#ifdef TEST_WEARABLE_DEVICE

class TestWearableClass : public WearableDevice {
public:
    TestWearableClass(SharedCommandData* sharedCommandData) : WearableDevice(sharedCommandData), done(false) {
        commandData command;
        command.type = KEYBOARD_COMMAND;
        command.kbd = UNDO;
        commandList.push_back(command);

        command.type = KEYBOARD_COMMAND;
        command.kbd = COPY;
        commandList.push_back(command);

        command.type = MOUSE_COMMAND;
        command.mouse = LEFT_CLICK;
        commandList.push_back(command);
    }

    void runDeviceLoop() {
        vector<commandData>::iterator it;

        WearableDevice::sharedData.setRelativeCoordinates(point(100, 50));
        for (it = commandList.begin(); it != commandList.end(); it++) {
            WearableDevice::sharedData.addCommand(*it);
           // this_thread::sleep_for(std::chrono::milliseconds(1000));
        }

        WearableDevice::sharedData.setRelativeCoordinates(point(10, 10));

        done = true;
    }

    bool isDone() { return done; }
private:
    vector<commandData> commandList;
    bool done;
};

int main() {
    SharedCommandData sharedData;
    TestWearableClass* testDevice = new TestWearableClass(&sharedData);

    // Kick off device thread
    startWearableDeviceListener(testDevice);

    while (true) {
        if (sharedData.isCommandQueueEmpty() && testDevice->isDone()) break;

        commandData nextCmd;
        while(!sharedData.consumeCommand(nextCmd));
        point nextPnt = sharedData.getRelativeCoordinates();

        cout << "Command: " << (nextCmd.type == MOUSE_COMMAND ? nextCmd.mouse : nextCmd.kbd)
            << ", Coords: (" << nextPnt.x << ", " << nextPnt.y << ")" << endl;
    }

    system("PAUSE");
    return 0;
}

#endif

#ifdef KEYBOARD_CONTROL_TEST
int main(void) {
    // new code :)

    // MANUAL TEST 1
    cout << "hijacking test main..." << endl;

    kybrdCtrl * controller = new kybrdCtrl();

    while (1) {
        keybd_event(VK_MENU, 0, 0, 0);// MapVirtualKey(VK_RMENU, MAPVK_VK_TO_VSC), 0, 0);
        Sleep(10);
        //keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC), 0, 0);
        //keybd_event(0x44, 0x20, 0, 0);
        //keybd_event(0x44, 0x20, KEYEVENTF_KEYUP, 0);
        keybd_event(VK_TAB, 0, 0, 0);// MapVirtualKey(0x4C, VK_TAB), 0, 0);
        Sleep(100);
        keybd_event(VK_TAB, 0, KEYEVENTF_KEYUP, 0);// MapVirtualKey(0x4C, VK_TAB), KEYEVENTF_KEYUP, 0);
        Sleep(10);
        //keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC), KEYEVENTF_KEYUP, 0);
        keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);// MapVirtualKey(VK_RMENU, MAPVK_VK_TO_VSC), KEYEVENTF_KEYUP, 0);

        Sleep(1000);
    }

    //while (1) {}

    /*controller->setKeyCmd(kybdCmds::HIDE_APPS);
    int status = controller->sendData();
    cout << "status = " << status << endl;

    Sleep(2000);

    controller->setKeyCmd(kybdCmds::WIN_HOME);
    status = controller->sendData();
    cout << "status = " << status << endl; */

    string blah;
    cin >> blah;

    int count = 0;
    while (true) {
        if (count++ % 2 == 0) {
            //controller->setKeyCmd(kybdCmds::ZOOM_IN);
            //controller->setKeyChar('a');
            controller->setKeyCmd(kybdCmds::SWITCH_WIN_FORWARD);
        }
        else {
            //controller->setKeyCmd(kybdCmds::ZOOM_OUT);
            //controller->setKeyChar('b');
            //controller->setKeyCmd(kybdCmds::SWITCH_WIN_REVERSE);
        }

        int status = controller->sendData();
        cout << "looping with opposite commands... status = " << status << endl;

        Sleep(1000);
    }

    system("PAUSE");
    return 0;
}
#endif
<commit_msg>taking out comment as per pull request #12345 commetns<commit_after>#include <iostream>
#include <string>
#include <Windows.h>
#include "kybrdCtrl.h"
#include "WearableDevice.h"
#include <vector>
#include <thread>

using namespace std;

#define KEYBOARD_CONTROL_TEST

#ifdef TEST_WEARABLE_DEVICE

class TestWearableClass : public WearableDevice {
public:
    TestWearableClass(SharedCommandData* sharedCommandData) : WearableDevice(sharedCommandData), done(false) {
        commandData command;
        command.type = KEYBOARD_COMMAND;
        command.kbd = UNDO;
        commandList.push_back(command);

        command.type = KEYBOARD_COMMAND;
        command.kbd = COPY;
        commandList.push_back(command);

        command.type = MOUSE_COMMAND;
        command.mouse = LEFT_CLICK;
        commandList.push_back(command);
    }

    void runDeviceLoop() {
        vector<commandData>::iterator it;

        WearableDevice::sharedData.setRelativeCoordinates(point(100, 50));
        for (it = commandList.begin(); it != commandList.end(); it++) {
            WearableDevice::sharedData.addCommand(*it);
           // this_thread::sleep_for(std::chrono::milliseconds(1000));
        }

        WearableDevice::sharedData.setRelativeCoordinates(point(10, 10));

        done = true;
    }

    bool isDone() { return done; }
private:
    vector<commandData> commandList;
    bool done;
};

int main() {
    SharedCommandData sharedData;
    TestWearableClass* testDevice = new TestWearableClass(&sharedData);

    // Kick off device thread
    startWearableDeviceListener(testDevice);

    while (true) {
        if (sharedData.isCommandQueueEmpty() && testDevice->isDone()) break;

        commandData nextCmd;
        while(!sharedData.consumeCommand(nextCmd));
        point nextPnt = sharedData.getRelativeCoordinates();

        cout << "Command: " << (nextCmd.type == MOUSE_COMMAND ? nextCmd.mouse : nextCmd.kbd)
            << ", Coords: (" << nextPnt.x << ", " << nextPnt.y << ")" << endl;
    }

    system("PAUSE");
    return 0;
}

#endif

#ifdef KEYBOARD_CONTROL_TEST
int main(void) {
    // MANUAL TEST 1
    cout << "hijacking test main..." << endl;

    kybrdCtrl * controller = new kybrdCtrl();

    while (1) {
        keybd_event(VK_MENU, 0, 0, 0);// MapVirtualKey(VK_RMENU, MAPVK_VK_TO_VSC), 0, 0);
        Sleep(10);
        //keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC), 0, 0);
        //keybd_event(0x44, 0x20, 0, 0);
        //keybd_event(0x44, 0x20, KEYEVENTF_KEYUP, 0);
        keybd_event(VK_TAB, 0, 0, 0);// MapVirtualKey(0x4C, VK_TAB), 0, 0);
        Sleep(100);
        keybd_event(VK_TAB, 0, KEYEVENTF_KEYUP, 0);// MapVirtualKey(0x4C, VK_TAB), KEYEVENTF_KEYUP, 0);
        Sleep(10);
        //keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC), KEYEVENTF_KEYUP, 0);
        keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);// MapVirtualKey(VK_RMENU, MAPVK_VK_TO_VSC), KEYEVENTF_KEYUP, 0);

        Sleep(1000);
    }

    //while (1) {}

    /*controller->setKeyCmd(kybdCmds::HIDE_APPS);
    int status = controller->sendData();
    cout << "status = " << status << endl;

    Sleep(2000);

    controller->setKeyCmd(kybdCmds::WIN_HOME);
    status = controller->sendData();
    cout << "status = " << status << endl; */

    string blah;
    cin >> blah;

    int count = 0;
    while (true) {
        if (count++ % 2 == 0) {
            //controller->setKeyCmd(kybdCmds::ZOOM_IN);
            //controller->setKeyChar('a');
            controller->setKeyCmd(kybdCmds::SWITCH_WIN_FORWARD);
        }
        else {
            //controller->setKeyCmd(kybdCmds::ZOOM_OUT);
            //controller->setKeyChar('b');
            //controller->setKeyCmd(kybdCmds::SWITCH_WIN_REVERSE);
        }

        int status = controller->sendData();
        cout << "looping with opposite commands... status = " << status << endl;

        Sleep(1000);
    }

    system("PAUSE");
    return 0;
}
#endif
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////
//
// Basic class for Performance/Calibration TRD tasks
//
// It performs generic tasks like :
//   - data file manegment
//   - reference container management
//   - debug container management
//   - interaction with AliAnalysisManager
//   - Plot functor loop
//
// Author: Alexandru Bercuci <A.Bercuci@gsi.de>, 10/09/2008
//
/////////////////////////////////////////////////////////

#include "TClass.h"
#include "TMethod.h"
#include "TMethodCall.h"
#include "TMethodArg.h"
#include "TFile.h"
#include "TChain.h"
#include "TList.h"
#include "TMap.h"
#include "TH1.h"
#include "TF1.h"
#include "TObjArray.h"
#include "TDirectory.h"
#include "TTreeStream.h"

#include "AliLog.h"
#include "AliAnalysisTask.h"

#include "AliTRDrecoTask.h"

ClassImp(AliTRDrecoTask)

TList* AliTRDrecoTask::fgTrendPoint(NULL);
TTreeSRedirector* AliTRDrecoTask::fgDebugStream(NULL);
//_______________________________________________________
AliTRDrecoTask::AliTRDrecoTask()
  : AliAnalysisTaskSE()
  ,fNRefFigures(0)
  ,fContainer(NULL)
  ,fTracks(NULL)
  ,fkTrack(NULL)
  ,fkMC(NULL)
  ,fkESD(NULL)
  ,fPlotFuncList(NULL)
{
// Default constructor
}

//_______________________________________________________
AliTRDrecoTask::AliTRDrecoTask(const char *name, const char *title)
  : AliAnalysisTaskSE(name)
  ,fNRefFigures(0)
  ,fContainer(NULL)
  ,fTracks(NULL)
  ,fkTrack(NULL)
  ,fkMC(NULL)
  ,fkESD(NULL)
  ,fPlotFuncList(NULL)
{
// Constructor for all derived performance tasks

  SetTitle(title);
  DefineInput (1, TObjArray::Class()); // track list
  DefineOutput(1, TObjArray::Class()); // histogram list
}

//_______________________________________________________
AliTRDrecoTask::~AliTRDrecoTask()
{

  // Generic task destructor

  AliDebug(2, Form(" Ending task %s[%s]", GetName(), GetTitle()));
  if(fgDebugStream){
    delete fgDebugStream;
    fgDebugStream = NULL;
  }

  if(fPlotFuncList){
    fPlotFuncList->Delete();
    delete fPlotFuncList;
    fPlotFuncList = NULL;
  }

  if(fContainer){
    if(fContainer->IsOwner()) fContainer->Delete();
    delete fContainer;
    fContainer = NULL;
  }

  if(fgTrendPoint){
    TFile::Open("TRD.PerformanceTrend.root", "UPDATE");
    fgTrendPoint->Write();
    delete fgTrendPoint;
    fgTrendPoint=NULL;
    gFile->Close();
  }
}

//_______________________________________________________
void AliTRDrecoTask::UserExec(Option_t *)
{
// Loop over Plot functors published by particular tasks

  fTracks = dynamic_cast<TObjArray *>(GetInputData(1));
  if(!fPlotFuncList){
    AliWarning("No functor list defined for the reference plots");
    return;
  }
  if(!fTracks) return;
  if(!fTracks->GetEntriesFast()) return;
  else AliDebug(2, Form("Tracks[%d] for %s", fTracks->GetEntriesFast(), GetName()));

  AliTRDtrackInfo *trackInfo = NULL;
  TIter plotIter(fPlotFuncList);
  TObjArrayIter trackIter(fTracks);
  while((trackInfo = dynamic_cast<AliTRDtrackInfo*>(trackIter()))){
    fkTrack = trackInfo->GetTrack();
    fkMC    = trackInfo->GetMCinfo();
    fkESD   = trackInfo->GetESDinfo();

    TMethodCall *plot = NULL;
    plotIter.Reset();
    while((plot=dynamic_cast<TMethodCall*>(plotIter()))){
      plot->Execute(this);
    }
  }
  PostData(1, fContainer);
}

//_______________________________________________________
Bool_t AliTRDrecoTask::GetRefFigure(Int_t /*ifig*/)
{
  AliWarning("Retrieving reference figures not implemented.");
  return kFALSE;
}

//_______________________________________________________
Bool_t AliTRDrecoTask::PutTrendValue(const Char_t *name, Double_t val)
{
// Generic publisher for trend values

  if(!fgTrendPoint){
    fgTrendPoint = new TList();
    fgTrendPoint->SetOwner();
  }
  fgTrendPoint->AddLast(new TNamed(Form("%s_%s", GetName(), name), Form("%f", val)));
  return kTRUE;
}

//_______________________________________________________
void AliTRDrecoTask::InitFunctorList()
{
// Initialize list of functors

  TClass *c = this->IsA();

  TMethod *m = NULL;
  TIter methIter(c->GetListOfMethods());
  while((m=dynamic_cast<TMethod*>(methIter()))){
    TString name(m->GetName());
    if(!name.BeginsWith("Plot")) continue;
    if(!fPlotFuncList) fPlotFuncList = new TList();
    fPlotFuncList->AddLast(new TMethodCall(c, (const char*)name, ""));
  }
}

//_______________________________________________________
Bool_t AliTRDrecoTask::Load(const Char_t *file, const Char_t *dir)
{
// Generic container loader

  if(!TFile::Open(file)){
    AliWarning(Form("Couldn't open file %s.", file));
    return kFALSE;
  }
  if(!gFile->cd(dir)){
    AliWarning(Form("Couldn't cd to %s in %s.", dir, file));
    return kFALSE;
  }
  TObjArray *o = NULL;
  if(!(o = (TObjArray*)gDirectory->Get(GetName()))){
    AliWarning("Missing histogram container.");
    return kFALSE;
  }
  fContainer = (TObjArray*)o->Clone(GetName());
  gFile->Close();
  return kTRUE;
}

//________________________________________________________
Bool_t AliTRDrecoTask::Save(TObjArray * const results){
  //
  // Store the output graphs in a ROOT file
  // Input TObject array will not be written as Key to the file,
  // only content itself
  //

  TDirectory *cwd = gDirectory;
  if(!TFile::Open(Form("TRD.Result%s.root", GetName()), "RECREATE")) return kFALSE;

  TIterator *iter = results->MakeIterator();
  TObject *inObject = NULL, *outObject = NULL;
  while((inObject = iter->Next())){
    outObject = inObject->Clone();
    outObject->Write(NULL, TObject::kSingleKey);
  }
  delete iter;
  gFile->Close(); delete gFile;
  cwd->cd();
  return kTRUE;
}

//_______________________________________________________
Bool_t AliTRDrecoTask::PostProcess()
{
// To be implemented by particular tasks

  AliWarning("Post processing of reference histograms not implemented.");
  return kFALSE;
}

//_______________________________________________________
void AliTRDrecoTask::MakeSummary(){
// To be implemented by particular tasks
  AliWarning("Summary not available");
}

//_______________________________________________________
void AliTRDrecoTask::SetDebugLevel(Int_t level)
{
// Generic debug handler

  AliAnalysisTaskSE::SetDebugLevel(level);
  if(DebugLevel()>=1){
    TDirectory *savedir = gDirectory;
    fgDebugStream = new TTreeSRedirector("TRD.DebugPerformance.root");
    savedir->cd();
  }
}

//____________________________________________________________________
void AliTRDrecoTask::Terminate(Option_t *)
{
  //
  // Terminate
  //

  if(fgDebugStream){
    delete fgDebugStream;
    fgDebugStream = NULL;
  }
  if(HasPostProcess()) PostProcess();
}

//________________________________________________________
void AliTRDrecoTask::Adjust(TF1 *f, TH1 * const h)
{
// Helper function to avoid duplication of code
// Make first guesses on the fit parameters

  // find the intial parameters of the fit !! (thanks George)
  Int_t nbinsy = Int_t(.5*h->GetNbinsX());
  Double_t sum = 0.;
  for(Int_t jbin=nbinsy-4; jbin<=nbinsy+4; jbin++) sum+=h->GetBinContent(jbin); sum/=9.;
  f->SetParLimits(0, 0., 3.*sum);
  f->SetParameter(0, .9*sum);

  f->SetParLimits(1, -.2, .2);
  f->SetParameter(1, -0.1);

  f->SetParLimits(2, 0., 4.e-1);
  f->SetParameter(2, 2.e-2);
  if(f->GetNpar() <= 4) return;

  f->SetParLimits(3, 0., sum);
  f->SetParameter(3, .1*sum);

  f->SetParLimits(4, -.3, .3);
  f->SetParameter(4, 0.);

  f->SetParLimits(5, 0., 1.e2);
  f->SetParameter(5, 2.e-1);
}
<commit_msg>use Terminate function for producing summary plots (Markus)<commit_after>///////////////////////////////////////////////////////
//
// Basic class for Performance/Calibration TRD tasks
//
// It performs generic tasks like :
//   - data file manegment
//   - reference container management
//   - debug container management
//   - interaction with AliAnalysisManager
//   - Plot functor loop
//
// Author: Alexandru Bercuci <A.Bercuci@gsi.de>, 10/09/2008
//
/////////////////////////////////////////////////////////

#include "TClass.h"
#include "TMethod.h"
#include "TMethodCall.h"
#include "TMethodArg.h"
#include "TFile.h"
#include "TChain.h"
#include "TList.h"
#include "TMap.h"
#include "TH1.h"
#include "TF1.h"
#include "TObjArray.h"
#include "TDirectory.h"
#include "TTreeStream.h"

#include "AliLog.h"
#include "AliAnalysisTask.h"

#include "AliTRDrecoTask.h"

ClassImp(AliTRDrecoTask)

TList* AliTRDrecoTask::fgTrendPoint(NULL);
TTreeSRedirector* AliTRDrecoTask::fgDebugStream(NULL);
//_______________________________________________________
AliTRDrecoTask::AliTRDrecoTask()
  : AliAnalysisTaskSE()
  ,fNRefFigures(0)
  ,fContainer(NULL)
  ,fTracks(NULL)
  ,fkTrack(NULL)
  ,fkMC(NULL)
  ,fkESD(NULL)
  ,fPlotFuncList(NULL)
{
// Default constructor
}

//_______________________________________________________
AliTRDrecoTask::AliTRDrecoTask(const char *name, const char *title)
  : AliAnalysisTaskSE(name)
  ,fNRefFigures(0)
  ,fContainer(NULL)
  ,fTracks(NULL)
  ,fkTrack(NULL)
  ,fkMC(NULL)
  ,fkESD(NULL)
  ,fPlotFuncList(NULL)
{
// Constructor for all derived performance tasks

  SetTitle(title);
  DefineInput (1, TObjArray::Class()); // track list
  DefineOutput(1, TObjArray::Class()); // histogram list
}

//_______________________________________________________
AliTRDrecoTask::~AliTRDrecoTask()
{

  // Generic task destructor

  AliDebug(2, Form(" Ending task %s[%s]", GetName(), GetTitle()));
  if(fgDebugStream){
    delete fgDebugStream;
    fgDebugStream = NULL;
  }

  if(fPlotFuncList){
    fPlotFuncList->Delete();
    delete fPlotFuncList;
    fPlotFuncList = NULL;
  }

  if(fContainer){
    if(fContainer->IsOwner()) fContainer->Delete();
    delete fContainer;
    fContainer = NULL;
  }

  if(fgTrendPoint){
    TFile::Open("TRD.PerformanceTrend.root", "UPDATE");
    fgTrendPoint->Write();
    delete fgTrendPoint;
    fgTrendPoint=NULL;
    gFile->Close();
  }
}

//_______________________________________________________
void AliTRDrecoTask::UserExec(Option_t *)
{
// Loop over Plot functors published by particular tasks

  fTracks = dynamic_cast<TObjArray *>(GetInputData(1));
  if(!fPlotFuncList){
    AliWarning("No functor list defined for the reference plots");
    return;
  }
  if(!fTracks) return;
  if(!fTracks->GetEntriesFast()) return;
  else AliDebug(2, Form("Tracks[%d] for %s", fTracks->GetEntriesFast(), GetName()));

  AliTRDtrackInfo *trackInfo = NULL;
  TIter plotIter(fPlotFuncList);
  TObjArrayIter trackIter(fTracks);
  while((trackInfo = dynamic_cast<AliTRDtrackInfo*>(trackIter()))){
    fkTrack = trackInfo->GetTrack();
    fkMC    = trackInfo->GetMCinfo();
    fkESD   = trackInfo->GetESDinfo();

    TMethodCall *plot = NULL;
    plotIter.Reset();
    while((plot=dynamic_cast<TMethodCall*>(plotIter()))){
      plot->Execute(this);
    }
  }
  PostData(1, fContainer);
}

//_______________________________________________________
Bool_t AliTRDrecoTask::GetRefFigure(Int_t /*ifig*/)
{
  AliWarning("Retrieving reference figures not implemented.");
  return kFALSE;
}

//_______________________________________________________
Bool_t AliTRDrecoTask::PutTrendValue(const Char_t *name, Double_t val)
{
// Generic publisher for trend values

  if(!fgTrendPoint){
    fgTrendPoint = new TList();
    fgTrendPoint->SetOwner();
  }
  fgTrendPoint->AddLast(new TNamed(Form("%s_%s", GetName(), name), Form("%f", val)));
  return kTRUE;
}

//_______________________________________________________
void AliTRDrecoTask::InitFunctorList()
{
// Initialize list of functors

  TClass *c = this->IsA();

  TMethod *m = NULL;
  TIter methIter(c->GetListOfMethods());
  while((m=dynamic_cast<TMethod*>(methIter()))){
    TString name(m->GetName());
    if(!name.BeginsWith("Plot")) continue;
    if(!fPlotFuncList) fPlotFuncList = new TList();
    fPlotFuncList->AddLast(new TMethodCall(c, (const char*)name, ""));
  }
}

//_______________________________________________________
Bool_t AliTRDrecoTask::Load(const Char_t *file, const Char_t *dir)
{
// Generic container loader

  if(!TFile::Open(file)){
    AliWarning(Form("Couldn't open file %s.", file));
    return kFALSE;
  }
  if(!gFile->cd(dir)){
    AliWarning(Form("Couldn't cd to %s in %s.", dir, file));
    return kFALSE;
  }
  TObjArray *o = NULL;
  if(!(o = (TObjArray*)gDirectory->Get(GetName()))){
    AliWarning("Missing histogram container.");
    return kFALSE;
  }
  fContainer = (TObjArray*)o->Clone(GetName());
  gFile->Close();
  return kTRUE;
}

//________________________________________________________
Bool_t AliTRDrecoTask::Save(TObjArray * const results){
  //
  // Store the output graphs in a ROOT file
  // Input TObject array will not be written as Key to the file,
  // only content itself
  //

  TDirectory *cwd = gDirectory;
  if(!TFile::Open(Form("TRD.Result%s.root", GetName()), "RECREATE")) return kFALSE;

  TIterator *iter = results->MakeIterator();
  TObject *inObject = NULL, *outObject = NULL;
  while((inObject = iter->Next())){
    outObject = inObject->Clone();
    outObject->Write(NULL, TObject::kSingleKey);
  }
  delete iter;
  gFile->Close(); delete gFile;
  cwd->cd();
  return kTRUE;
}

//_______________________________________________________
Bool_t AliTRDrecoTask::PostProcess()
{
// To be implemented by particular tasks

  AliWarning("Post processing of reference histograms not implemented.");
  return kFALSE;
}

//_______________________________________________________
void AliTRDrecoTask::MakeSummary(){
// To be implemented by particular tasks
  AliWarning("Summary not available");
}

//_______________________________________________________
void AliTRDrecoTask::SetDebugLevel(Int_t level)
{
// Generic debug handler

  AliAnalysisTaskSE::SetDebugLevel(level);
  if(DebugLevel()>=1){
    TDirectory *savedir = gDirectory;
    fgDebugStream = new TTreeSRedirector("TRD.DebugPerformance.root");
    savedir->cd();
  }
}

//____________________________________________________________________
void AliTRDrecoTask::Terminate(Option_t *)
{
  //
  // Terminate
  //

  if(fgDebugStream){
    delete fgDebugStream;
    fgDebugStream = NULL;
  }
  fContainer = dynamic_cast<TObjArray *>(GetOutputData(1));
  PostProcess();
  MakeSummary();
}

//________________________________________________________
void AliTRDrecoTask::Adjust(TF1 *f, TH1 * const h)
{
// Helper function to avoid duplication of code
// Make first guesses on the fit parameters

  // find the intial parameters of the fit !! (thanks George)
  Int_t nbinsy = Int_t(.5*h->GetNbinsX());
  Double_t sum = 0.;
  for(Int_t jbin=nbinsy-4; jbin<=nbinsy+4; jbin++) sum+=h->GetBinContent(jbin); sum/=9.;
  f->SetParLimits(0, 0., 3.*sum);
  f->SetParameter(0, .9*sum);

  f->SetParLimits(1, -.2, .2);
  f->SetParameter(1, -0.1);

  f->SetParLimits(2, 0., 4.e-1);
  f->SetParameter(2, 2.e-2);
  if(f->GetNpar() <= 4) return;

  f->SetParLimits(3, 0., sum);
  f->SetParameter(3, .1*sum);

  f->SetParLimits(4, -.3, .3);
  f->SetParameter(4, 0.);

  f->SetParLimits(5, 0., 1.e2);
  f->SetParameter(5, 2.e-1);
}
<|endoftext|>


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

#include <thrift/lib/cpp2/transport/rocket/framing/Flags.h>

#include <folly/portability/GTest.h>

using namespace apache::thrift::rocket;

TEST(FlagsTest, setting) {
  Flags flags;

  EXPECT_FALSE(flags.ignore());
  flags.ignore(true);
  EXPECT_TRUE(flags.ignore());
  flags.ignore(false);
  EXPECT_FALSE(flags.ignore());
}

TEST(FlagsTest, lowestFlag) {
  Flags flags;

  EXPECT_FALSE(flags.next());
  flags.next(true);
  EXPECT_TRUE(flags.next());
}

TEST(FlagsTest, invalidFlags) {
  // Flags use the lower 10 bits, as specified in rsocket
  EXPECT_EQ(Flags::kBits, 10);

  uint16_t over = 1 << Flags::kBits;
  uint16_t under = 1 << (Flags::kUnusedBits - 1);
  uint16_t allowed = 1 << (Flags::kBits - 1);

  auto mk = [](uint16_t bits) {
    Flags f(bits);
    (void)f;
  };

  EXPECT_NO_THROW(mk(0));

  EXPECT_DEATH(mk(over), "Check failed");
  EXPECT_THROW(mk(under), std::runtime_error);
  EXPECT_NO_THROW(mk(allowed));

  EXPECT_DEATH(mk(over | allowed), "Check failed");
  EXPECT_THROW(mk(under | allowed), std::runtime_error);
  EXPECT_DEATH(mk(over | under), "Check failed");

  EXPECT_DEATH(mk(over | under | allowed), "Check failed");
}
<commit_msg>Fix opt tests<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <thrift/lib/cpp2/transport/rocket/framing/Flags.h>

#include <folly/portability/GTest.h>

using namespace apache::thrift::rocket;

TEST(FlagsTest, setting) {
  Flags flags;

  EXPECT_FALSE(flags.ignore());
  flags.ignore(true);
  EXPECT_TRUE(flags.ignore());
  flags.ignore(false);
  EXPECT_FALSE(flags.ignore());
}

TEST(FlagsTest, lowestFlag) {
  Flags flags;

  EXPECT_FALSE(flags.next());
  flags.next(true);
  EXPECT_TRUE(flags.next());
}

TEST(FlagsTest, invalidFlags) {
  // Flags use the lower 10 bits, as specified in rsocket
  EXPECT_EQ(Flags::kBits, 10);

  uint16_t over = 1 << Flags::kBits;
  uint16_t under = 1 << (Flags::kUnusedBits - 1);
  uint16_t allowed = 1 << (Flags::kBits - 1);

  auto mk = [](uint16_t bits) {
    Flags f(bits);
    (void)f;
  };

  EXPECT_NO_THROW(mk(0));
  EXPECT_NO_THROW(mk(allowed));

  // DCHECK is turned off in opt mode, so overs will not die
#ifndef NDEBUG
  EXPECT_DEATH(mk(over), "Check failed");
  EXPECT_DEATH(mk(over | allowed), "Check failed");
  EXPECT_DEATH(mk(over | under), "Check failed");
  EXPECT_DEATH(mk(over | under | allowed), "Check failed");
#else
  EXPECT_NO_THROW(mk(over));
  EXPECT_NO_THROW(mk(over | allowed));

  EXPECT_THROW(mk(over | under), std::runtime_error);
  EXPECT_THROW(mk(over | under | allowed), std::runtime_error);
#endif

  EXPECT_THROW(mk(under), std::runtime_error);
  EXPECT_THROW(mk(under | allowed), std::runtime_error);
}
<|endoftext|>