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

/**
 * @file mixer.cpp
 *
 * Control channel input/output mixer and failsafe.
 */

#include <nuttx/config.h>
#include <nuttx/arch.h>

#include <sys/types.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#include <drivers/drv_pwm_output.h>
#include <systemlib/mixer/mixer.h>

extern "C" {
#include "px4io.h"
}

/*
 * Count of periodic calls in which we have no FMU input.
 */
static unsigned fmu_input_drops;
#define FMU_INPUT_DROP_LIMIT	20

/* current servo arm/disarm state */
bool mixer_servos_armed = false;

/* selected control values and count for mixing */
static uint16_t *control_values;
static int control_count;

static int	mixer_callback(uintptr_t handle,
			uint8_t control_group,
			uint8_t control_index,
			float &control);

static MixerGroup mixer_group(mixer_callback, 0);

void
mixer_tick(void)
{
	bool should_arm;

	/*
	 * Decide which set of inputs we're using.
	 */
	if (system_state.mixer_use_fmu) {
		/* we have recent control data from the FMU */
		control_count = PX4IO_OUTPUT_CHANNELS;
		control_values = &system_state.fmu_channel_data[0];

		/* check that we are receiving fresh data from the FMU */
		if (!system_state.fmu_data_received) {
			fmu_input_drops++;

			/* too many frames without FMU input, time to go to failsafe */
			if (fmu_input_drops >= FMU_INPUT_DROP_LIMIT) {
				system_state.mixer_use_fmu = false;
			}
		} else {
			fmu_input_drops = 0;
			system_state.fmu_data_received = false;
		}

	} else if (system_state.rc_channels > 0) {
		/* we have control data from an R/C input */
		control_count = system_state.rc_channels;
		control_values = &system_state.rc_channel_data[0];

	} else {
		/* we have no control input */
		/* XXX builtin failsafe would activate here */
		control_count = 0;
	}

	/*
	 * Run the mixers if we have any control data at all.
	 */
	if (control_count > 0) {
		float	outputs[IO_SERVO_COUNT];
		unsigned mixed;

		/* mix */
		mixed = mixer_group.mix(&outputs[0], IO_SERVO_COUNT);

		/* scale to PWM and update the servo outputs as required */
		for (unsigned i = 0; i < IO_SERVO_COUNT; i++) {
			if (i < mixed) {
				/* scale to servo output */
				system_state.servos[i] = (outputs[i] * 1000.0f) + 1000;
			} else {
				/* set to zero to inhibit PWM pulse output */
				system_state.servos[i] = 0;
			}

			/*
			 * If we are armed, update the servo output.
			 */
			if (system_state.armed && system_state.arm_ok)
				up_pwm_servo_set(i, system_state.servos[i]);
		}
	}

	/*
	 * Decide whether the servos should be armed right now.
	 */
	should_arm = system_state.armed && system_state.arm_ok && (control_count > 0);
	if (should_arm && !mixer_servos_armed) {
		/* need to arm, but not armed */
		up_pwm_servo_arm(true);
		mixer_servos_armed = true;

	} else if (!should_arm && mixer_servos_armed) {
		/* armed but need to disarm */
		up_pwm_servo_arm(false);
		mixer_servos_armed = false;
	}
}

static int
mixer_callback(uintptr_t handle,
	       uint8_t control_group,
	       uint8_t control_index,
	       float &control)
{
	/* if the control index refers to an input that's not valid, we can't return it */
	if (control_index >= control_count)
		return -1;

	/* scale from current PWM units (1000-2000) to mixer input values */
	/* XXX this presents some ugly problems w.r.t failsafe and R/C input scaling that have to be addressed */
	control = ((float)control_values[control_index] - 1000.0f) / 1000.0f;

	return 0;
}

void
mixer_handle_text(const void *buffer, size_t length)
{
	static char mixer_text[256];
	static unsigned mixer_text_length = 0;

	px4io_mixdata	*msg = (px4io_mixdata *)buffer;
	if (length < sizeof(px4io_mixdata))
		return;

	unsigned	text_length = length - sizeof(px4io_mixdata);

	switch (msg->action) {
	case F2I_MIXER_ACTION_RESET:
		mixer_group.reset();
		mixer_text_length = 0;
		/* FALLTHROUGH */
	case F2I_MIXER_ACTION_APPEND:
		/* check for overflow - this is really fatal */
		if ((mixer_text_length + text_length + 1) > sizeof(mixer_text))
			return;

		/* append mixer text and nul-terminate */
		memcpy(&mixer_text[mixer_text_length], msg->text, text_length);
		mixer_text_length += text_length;
		mixer_text[mixer_text_length] = '\0';

		/* process the text buffer, adding new mixers as their descriptions can be parsed */
		char *end = &mixer_text[mixer_text_length];
		mixer_group.load_from_buf(&mixer_text[0], mixer_text_length);

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

/**
 * @file mixer.cpp
 *
 * Control channel input/output mixer and failsafe.
 */

#include <nuttx/config.h>
#include <nuttx/arch.h>

#include <sys/types.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#include <drivers/drv_pwm_output.h>
#include <systemlib/mixer/mixer.h>

extern "C" {
#include "px4io.h"
}

/*
 * Count of periodic calls in which we have no FMU input.
 */
static unsigned fmu_input_drops;
#define FMU_INPUT_DROP_LIMIT	20

/* current servo arm/disarm state */
bool mixer_servos_armed = false;

/* selected control values and count for mixing */
static uint16_t *control_values;
static int control_count;

static int	mixer_callback(uintptr_t handle,
			uint8_t control_group,
			uint8_t control_index,
			float &control);

static MixerGroup mixer_group(mixer_callback, 0);

void
mixer_tick(void)
{
	bool should_arm;

	/*
	 * Decide which set of inputs we're using.
	 */
	if (system_state.mixer_use_fmu) {
		/* we have recent control data from the FMU */
		control_count = PX4IO_OUTPUT_CHANNELS;
		control_values = &system_state.fmu_channel_data[0];

		/* check that we are receiving fresh data from the FMU */
		if (!system_state.fmu_data_received) {
			fmu_input_drops++;

			/* too many frames without FMU input, time to go to failsafe */
			if (fmu_input_drops >= FMU_INPUT_DROP_LIMIT) {
				system_state.mixer_use_fmu = false;
			}
		} else {
			fmu_input_drops = 0;
			system_state.fmu_data_received = false;
		}

	} else if (system_state.rc_channels > 0) {
		/* we have control data from an R/C input */
		control_count = system_state.rc_channels;
		control_values = &system_state.rc_channel_data[0];

	} else {
		/* we have no control input */
		/* XXX builtin failsafe would activate here */
		control_count = 0;
	}

	/*
	 * Run the mixers if we have any control data at all.
	 */
	if (control_count > 0) {
		float	outputs[IO_SERVO_COUNT];
		unsigned mixed;

		/* mix */
		mixed = mixer_group.mix(&outputs[0], IO_SERVO_COUNT);

		/* scale to PWM and update the servo outputs as required */
		for (unsigned i = 0; i < IO_SERVO_COUNT; i++) {
			if (i < mixed) {
				/* scale to servo output */
				system_state.servos[i] = (outputs[i] * 500.0f) + 1500;
			} else {
				/* set to zero to inhibit PWM pulse output */
				system_state.servos[i] = 0;
			}

			/*
			 * If we are armed, update the servo output.
			 */
			if (system_state.armed && system_state.arm_ok)
				up_pwm_servo_set(i, system_state.servos[i]);
		}
	}

	/*
	 * Decide whether the servos should be armed right now.
	 */
	should_arm = system_state.armed && system_state.arm_ok && (control_count > 0);
	if (should_arm && !mixer_servos_armed) {
		/* need to arm, but not armed */
		up_pwm_servo_arm(true);
		mixer_servos_armed = true;

	} else if (!should_arm && mixer_servos_armed) {
		/* armed but need to disarm */
		up_pwm_servo_arm(false);
		mixer_servos_armed = false;
	}
}

static int
mixer_callback(uintptr_t handle,
	       uint8_t control_group,
	       uint8_t control_index,
	       float &control)
{
	/* if the control index refers to an input that's not valid, we can't return it */
	if (control_index >= control_count)
		return -1;

	/* scale from current PWM units (1000-2000) to mixer input values */
	/* XXX this presents some ugly problems w.r.t failsafe and R/C input scaling that have to be addressed */
	control = ((float)control_values[control_index] - 1500.0f) / 500.0f;

	return 0;
}

void
mixer_handle_text(const void *buffer, size_t length)
{
	static char mixer_text[256];
	static unsigned mixer_text_length = 0;

	px4io_mixdata	*msg = (px4io_mixdata *)buffer;
	if (length < sizeof(px4io_mixdata))
		return;

	unsigned	text_length = length - sizeof(px4io_mixdata);

	switch (msg->action) {
	case F2I_MIXER_ACTION_RESET:
		mixer_group.reset();
		mixer_text_length = 0;
		/* FALLTHROUGH */
	case F2I_MIXER_ACTION_APPEND:
		/* check for overflow - this is really fatal */
		if ((mixer_text_length + text_length + 1) > sizeof(mixer_text))
			return;

		/* append mixer text and nul-terminate */
		memcpy(&mixer_text[mixer_text_length], msg->text, text_length);
		mixer_text_length += text_length;
		mixer_text[mixer_text_length] = '\0';

		/* process the text buffer, adding new mixers as their descriptions can be parsed */
		char *end = &mixer_text[mixer_text_length];
		mixer_group.load_from_buf(&mixer_text[0], mixer_text_length);

		/* copy any leftover text to the base of the buffer for re-use */
		if (mixer_text_length > 0)
			memcpy(&mixer_text[0], end - mixer_text_length, mixer_text_length);
		break;
	}
}<|endoftext|>


<commit_before>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011-2013                                                    *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa is free software: you can redistribute it and/or modify it under   *
 * the terms of the GNU Lesser General Public License as published by the     *
 * Free Software Foundation; either version 2.1 of the License,               *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa is distributed in the hope that it will be useful,                 *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                       *
 * See the GNU Lesser General Public License for more details.                *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_OPTION_HPP
#define CPPA_OPTION_HPP

#include <new>
#include <utility>

#include "cppa/none.hpp"
#include "cppa/unit.hpp"
#include "cppa/config.hpp"

namespace cppa {

/**
 * @brief Represents an optional value of @p T.
 */
template<typename T>
class optional {

 public:

    /**
     * @brief Typdef for @p T.
     */
    typedef T type;

    /* *
     * @brief Default constructor.
     * @post <tt>valid() == false</tt>
     */
    //optional() : m_valid(false) { }

    /**
     * @post <tt>valid() == false</tt>
     */
    optional(const none_t&) : m_valid(false) { }

    /**
     * @brief Creates an @p option from @p value.
     * @post <tt>valid() == true</tt>
     */
    optional(T value) : m_valid(false) { cr(std::move(value)); }

    optional(const optional& other) : m_valid(false) {
        if (other.m_valid) cr(other.m_value);
    }

    optional(optional&& other) : m_valid(false) {
        if (other.m_valid) cr(std::move(other.m_value));
    }

    ~optional() { destroy(); }

    optional& operator=(const optional& other) {
        if (m_valid) {
            if (other.m_valid) m_value = other.m_value;
            else destroy();
        }
        else if (other.m_valid) {
            cr(other.m_value);
        }
        return *this;
    }

    optional& operator=(optional&& other) {
        if (m_valid) {
            if (other.m_valid) m_value = std::move(other.m_value);
            else destroy();
        }
        else if (other.m_valid) {
            cr(std::move(other.m_value));
        }
        return *this;
    }

    /**
     * @brief Returns @p true if this @p option has a valid value;
     *        otherwise @p false.
     */
    inline bool valid() const { return m_valid; }

    /**
     * @brief Returns <tt>!valid()</tt>.
     */
    inline bool empty() const { return !m_valid; }

    /**
     * @copydoc valid()
     */
    inline explicit operator bool() const { return valid(); }

    /**
     * @brief Returns <tt>!valid()</tt>.
     */
    inline bool operator!() const { return empty(); }

    inline bool operator==(const none_t&) { return empty(); }

    /**
     * @brief Returns the value.
     */
    inline T& operator*() {
        CPPA_REQUIRE(valid());
        return m_value;
    }

    /**
     * @brief Returns the value.
     */
    inline const T& operator*() const {
        CPPA_REQUIRE(valid());
        return m_value;
    }

    /**
     * @brief Returns the value.
     */
    inline T& get() {
        CPPA_REQUIRE(valid());
        return m_value;
    }

    /**
     * @brief Returns the value.
     */
    inline const T& get() const {
        CPPA_REQUIRE(valid());
        return m_value;
    }

    /**
     * @brief Returns the value. The value is set to @p default_value
     *        if <tt>valid() == false</tt>.
     * @post <tt>valid() == true</tt>
     */
    inline const T& get_or_else(const T& default_value) const {
        if (valid()) return get();
        return default_value;
    }

 private:

    bool m_valid;
    union { T m_value; };

    void destroy() {
        if (m_valid) {
            m_value.~T();
            m_valid = false;
        }
    }

    template<typename V>
    void cr(V&& value) {
        CPPA_REQUIRE(!valid());
        m_valid = true;
        new (&m_value) T (std::forward<V>(value));
    }

};

template<typename T>
class optional<T&> {

 public:

    typedef T type;

    optional() : m_value(nullptr) { }

    optional(T& value) : m_value(&value) { }

    optional(const optional& other) = default;

    optional& operator=(const optional& other) = default;

    inline bool valid() const { return m_value != nullptr; }

    inline bool empty() const { return !valid(); }

    inline explicit operator bool() const { return valid(); }

    inline bool operator!() const { return empty(); }

    inline bool operator==(const none_t&) { return empty(); }

    inline T& operator*() {
        CPPA_REQUIRE(valid());
        return *m_value;
    }

    inline const T& operator*() const {
        CPPA_REQUIRE(valid());
        return *m_value;
    }

    inline T& get() {
        CPPA_REQUIRE(valid());
        return *m_value;
    }

    inline const T& get() const {
        CPPA_REQUIRE(valid());
        return *m_value;
    }

    inline const T& get_or_else(const T& default_value) const {
        if (valid()) return get();
        return default_value;
    }

 private:

    T* m_value;

};

template<>
class optional<void> {

 public:

    optional(const unit_t&) : m_valid(true) { }

    optional(const none_t&) : m_valid(false) { }

    inline bool valid() const { return m_valid; }

    inline bool empty() const { return !m_valid; }

    inline explicit operator bool() const { return valid(); }

    inline bool operator!() const { return empty(); }

    inline bool operator==(const none_t&) { return empty(); }

    inline const unit_t& operator*() const { return unit; }

 private:

    bool m_valid;

};

/** @relates option */
template<typename T>
struct is_optional { static constexpr bool value = false; };

template<typename T>
struct is_optional<optional<T>> { static constexpr bool value = true; };

/** @relates option */
template<typename T, typename U>
bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
    if ((lhs) && (rhs)) return *lhs == *rhs;
    return false;
}

/** @relates option */
template<typename T, typename U>
bool operator==(const optional<T>& lhs, const U& rhs) {
    if (lhs) return *lhs == rhs;
    return false;
}

/** @relates option */
template<typename T, typename U>
bool operator==(const T& lhs, const optional<U>& rhs) {
    return rhs == lhs;
}

/** @relates option */
template<typename T, typename U>
bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
    return !(lhs == rhs);
}

/** @relates option */
template<typename T, typename U>
bool operator!=(const optional<T>& lhs, const U& rhs) {
    return !(lhs == rhs);
}

/** @relates option */
template<typename T, typename U>
bool operator!=(const T& lhs, const optional<U>& rhs) {
    return !(lhs == rhs);
}

} // namespace cppa

#endif // CPPA_OPTION_HPP
<commit_msg>Allow for default construction of optional<T>.<commit_after>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011-2013                                                    *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa is free software: you can redistribute it and/or modify it under   *
 * the terms of the GNU Lesser General Public License as published by the     *
 * Free Software Foundation; either version 2.1 of the License,               *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa is distributed in the hope that it will be useful,                 *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                       *
 * See the GNU Lesser General Public License for more details.                *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_OPTION_HPP
#define CPPA_OPTION_HPP

#include <new>
#include <utility>

#include "cppa/none.hpp"
#include "cppa/unit.hpp"
#include "cppa/config.hpp"

namespace cppa {

/**
 * @brief Represents an optional value of @p T.
 */
template<typename T>
class optional {

 public:

    /**
     * @brief Typdef for @p T.
     */
    typedef T type;

    /* *
     * @brief Default constructor.
     * @post <tt>valid() == false</tt>
     */
    //optional() : m_valid(false) { }

    /**
     * @post <tt>valid() == false</tt>
     */
    optional(const none_t& = none) : m_valid(false) { }

    /**
     * @brief Creates an @p option from @p value.
     * @post <tt>valid() == true</tt>
     */
    optional(T value) : m_valid(false) { cr(std::move(value)); }

    optional(const optional& other) : m_valid(false) {
        if (other.m_valid) cr(other.m_value);
    }

    optional(optional&& other) : m_valid(false) {
        if (other.m_valid) cr(std::move(other.m_value));
    }

    ~optional() { destroy(); }

    optional& operator=(const optional& other) {
        if (m_valid) {
            if (other.m_valid) m_value = other.m_value;
            else destroy();
        }
        else if (other.m_valid) {
            cr(other.m_value);
        }
        return *this;
    }

    optional& operator=(optional&& other) {
        if (m_valid) {
            if (other.m_valid) m_value = std::move(other.m_value);
            else destroy();
        }
        else if (other.m_valid) {
            cr(std::move(other.m_value));
        }
        return *this;
    }

    /**
     * @brief Returns @p true if this @p option has a valid value;
     *        otherwise @p false.
     */
    inline bool valid() const { return m_valid; }

    /**
     * @brief Returns <tt>!valid()</tt>.
     */
    inline bool empty() const { return !m_valid; }

    /**
     * @copydoc valid()
     */
    inline explicit operator bool() const { return valid(); }

    /**
     * @brief Returns <tt>!valid()</tt>.
     */
    inline bool operator!() const { return empty(); }

    inline bool operator==(const none_t&) { return empty(); }

    /**
     * @brief Returns the value.
     */
    inline T& operator*() {
        CPPA_REQUIRE(valid());
        return m_value;
    }

    /**
     * @brief Returns the value.
     */
    inline const T& operator*() const {
        CPPA_REQUIRE(valid());
        return m_value;
    }

    /**
     * @brief Returns the value.
     */
    inline T& get() {
        CPPA_REQUIRE(valid());
        return m_value;
    }

    /**
     * @brief Returns the value.
     */
    inline const T& get() const {
        CPPA_REQUIRE(valid());
        return m_value;
    }

    /**
     * @brief Returns the value. The value is set to @p default_value
     *        if <tt>valid() == false</tt>.
     * @post <tt>valid() == true</tt>
     */
    inline const T& get_or_else(const T& default_value) const {
        if (valid()) return get();
        return default_value;
    }

 private:

    bool m_valid;
    union { T m_value; };

    void destroy() {
        if (m_valid) {
            m_value.~T();
            m_valid = false;
        }
    }

    template<typename V>
    void cr(V&& value) {
        CPPA_REQUIRE(!valid());
        m_valid = true;
        new (&m_value) T (std::forward<V>(value));
    }

};

template<typename T>
class optional<T&> {

 public:

    typedef T type;

    optional() : m_value(nullptr) { }

    optional(T& value) : m_value(&value) { }

    optional(const optional& other) = default;

    optional& operator=(const optional& other) = default;

    inline bool valid() const { return m_value != nullptr; }

    inline bool empty() const { return !valid(); }

    inline explicit operator bool() const { return valid(); }

    inline bool operator!() const { return empty(); }

    inline bool operator==(const none_t&) { return empty(); }

    inline T& operator*() {
        CPPA_REQUIRE(valid());
        return *m_value;
    }

    inline const T& operator*() const {
        CPPA_REQUIRE(valid());
        return *m_value;
    }

    inline T& get() {
        CPPA_REQUIRE(valid());
        return *m_value;
    }

    inline const T& get() const {
        CPPA_REQUIRE(valid());
        return *m_value;
    }

    inline const T& get_or_else(const T& default_value) const {
        if (valid()) return get();
        return default_value;
    }

 private:

    T* m_value;

};

template<>
class optional<void> {

 public:

    optional(const unit_t&) : m_valid(true) { }

    optional(const none_t&) : m_valid(false) { }

    inline bool valid() const { return m_valid; }

    inline bool empty() const { return !m_valid; }

    inline explicit operator bool() const { return valid(); }

    inline bool operator!() const { return empty(); }

    inline bool operator==(const none_t&) { return empty(); }

    inline const unit_t& operator*() const { return unit; }

 private:

    bool m_valid;

};

/** @relates option */
template<typename T>
struct is_optional { static constexpr bool value = false; };

template<typename T>
struct is_optional<optional<T>> { static constexpr bool value = true; };

/** @relates option */
template<typename T, typename U>
bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
    if ((lhs) && (rhs)) return *lhs == *rhs;
    return false;
}

/** @relates option */
template<typename T, typename U>
bool operator==(const optional<T>& lhs, const U& rhs) {
    if (lhs) return *lhs == rhs;
    return false;
}

/** @relates option */
template<typename T, typename U>
bool operator==(const T& lhs, const optional<U>& rhs) {
    return rhs == lhs;
}

/** @relates option */
template<typename T, typename U>
bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
    return !(lhs == rhs);
}

/** @relates option */
template<typename T, typename U>
bool operator!=(const optional<T>& lhs, const U& rhs) {
    return !(lhs == rhs);
}

/** @relates option */
template<typename T, typename U>
bool operator!=(const T& lhs, const optional<U>& rhs) {
    return !(lhs == rhs);
}

} // namespace cppa

#endif // CPPA_OPTION_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/download_shelf.h"

#include "app/l10n_util.h"
#include "base/file_util.h"
#include "chrome/browser/dom_ui/downloads_ui.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

#if defined(OS_WIN)
#include "chrome/browser/download/download_util.h"
#elif defined(OS_POSIX)
#include "chrome/common/temp_scaffolding_stubs.h"
#endif

// DownloadShelf ---------------------------------------------------------------

void DownloadShelf::ShowAllDownloads() {
  Profile* profile = tab_contents_->profile();
  if (profile)
    UserMetrics::RecordAction(L"ShowDownloads", profile);
  tab_contents_->OpenURL(GURL(chrome::kChromeUIDownloadsURL), GURL(),
                         SINGLETON_TAB, PageTransition::AUTO_BOOKMARK);
}

void DownloadShelf::ChangeTabContents(TabContents* old_contents,
                                      TabContents* new_contents) {
  DCHECK(old_contents == tab_contents_);
  tab_contents_ = new_contents;
}

// DownloadShelfContextMenu ----------------------------------------------------

DownloadShelfContextMenu::DownloadShelfContextMenu(
    BaseDownloadItemModel* download_model)
    : download_(download_model->download()),
      model_(download_model) {
}

DownloadShelfContextMenu::~DownloadShelfContextMenu() {
}

bool DownloadShelfContextMenu::ItemIsChecked(int id) const {
  switch (id) {
    case OPEN_WHEN_COMPLETE:
      return download_->open_when_complete();
    case ALWAYS_OPEN_TYPE: {
      const FilePath::StringType extension =
          file_util::GetFileExtensionFromPath(download_->full_path());
      return download_->manager()->ShouldOpenFileExtension(extension);
    }
  }
  return false;
}

bool DownloadShelfContextMenu::ItemIsDefault(int id) const {
  return id == OPEN_WHEN_COMPLETE;
}

std::wstring DownloadShelfContextMenu::GetItemLabel(int id) const {
  switch (id) {
    case SHOW_IN_FOLDER:
      return l10n_util::GetString(IDS_DOWNLOAD_LINK_SHOW);
    case OPEN_WHEN_COMPLETE:
      if (download_->state() == DownloadItem::IN_PROGRESS)
        return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN);
    case ALWAYS_OPEN_TYPE:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
    case CANCEL:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_CANCEL);
    default:
      NOTREACHED();
  }
  return std::wstring();
}

bool DownloadShelfContextMenu::IsItemCommandEnabled(int id) const {
  switch (id) {
    case SHOW_IN_FOLDER:
    case OPEN_WHEN_COMPLETE:
      return download_->state() != DownloadItem::CANCELLED;
    case ALWAYS_OPEN_TYPE:
#if defined(OS_WIN)
      return download_util::CanOpenDownload(download_);
#else
      // TODO(port): port download_util
      NOTIMPLEMENTED();
      return true;
#endif
    case CANCEL:
      return download_->state() == DownloadItem::IN_PROGRESS;
    default:
      return id > 0 && id < MENU_LAST;
  }
}

void DownloadShelfContextMenu::ExecuteItemCommand(int id) {
  switch (id) {
    case SHOW_IN_FOLDER:
      download_->manager()->ShowDownloadInShell(download_);
      break;
    case OPEN_WHEN_COMPLETE:
#if defined(OS_WIN)
      download_util::OpenDownload(download_);
#else
      // TODO(port): port download_util
      NOTIMPLEMENTED();
#endif
      break;
    case ALWAYS_OPEN_TYPE: {
      const FilePath::StringType extension =
          file_util::GetFileExtensionFromPath(download_->full_path());
      download_->manager()->OpenFilesOfExtension(
          extension, !ItemIsChecked(ALWAYS_OPEN_TYPE));
      break;
    }
    case CANCEL:
      model_->CancelTask();
      break;
    default:
      NOTREACHED();
  }
}
<commit_msg>Remove one more notimpl.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/download_shelf.h"

#include "app/l10n_util.h"
#include "base/file_util.h"
#include "chrome/browser/dom_ui/downloads_ui.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"

#if defined(OS_WIN)
#include "chrome/browser/download/download_util.h"
#elif defined(OS_POSIX)
#include "chrome/common/temp_scaffolding_stubs.h"
#endif

// DownloadShelf ---------------------------------------------------------------

void DownloadShelf::ShowAllDownloads() {
  Profile* profile = tab_contents_->profile();
  if (profile)
    UserMetrics::RecordAction(L"ShowDownloads", profile);
  tab_contents_->OpenURL(GURL(chrome::kChromeUIDownloadsURL), GURL(),
                         SINGLETON_TAB, PageTransition::AUTO_BOOKMARK);
}

void DownloadShelf::ChangeTabContents(TabContents* old_contents,
                                      TabContents* new_contents) {
  DCHECK(old_contents == tab_contents_);
  tab_contents_ = new_contents;
}

// DownloadShelfContextMenu ----------------------------------------------------

DownloadShelfContextMenu::DownloadShelfContextMenu(
    BaseDownloadItemModel* download_model)
    : download_(download_model->download()),
      model_(download_model) {
}

DownloadShelfContextMenu::~DownloadShelfContextMenu() {
}

bool DownloadShelfContextMenu::ItemIsChecked(int id) const {
  switch (id) {
    case OPEN_WHEN_COMPLETE:
      return download_->open_when_complete();
    case ALWAYS_OPEN_TYPE: {
      const FilePath::StringType extension =
          file_util::GetFileExtensionFromPath(download_->full_path());
      return download_->manager()->ShouldOpenFileExtension(extension);
    }
  }
  return false;
}

bool DownloadShelfContextMenu::ItemIsDefault(int id) const {
  return id == OPEN_WHEN_COMPLETE;
}

std::wstring DownloadShelfContextMenu::GetItemLabel(int id) const {
  switch (id) {
    case SHOW_IN_FOLDER:
      return l10n_util::GetString(IDS_DOWNLOAD_LINK_SHOW);
    case OPEN_WHEN_COMPLETE:
      if (download_->state() == DownloadItem::IN_PROGRESS)
        return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE);
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_OPEN);
    case ALWAYS_OPEN_TYPE:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_ALWAYS_OPEN_TYPE);
    case CANCEL:
      return l10n_util::GetString(IDS_DOWNLOAD_MENU_CANCEL);
    default:
      NOTREACHED();
  }
  return std::wstring();
}

bool DownloadShelfContextMenu::IsItemCommandEnabled(int id) const {
  switch (id) {
    case SHOW_IN_FOLDER:
    case OPEN_WHEN_COMPLETE:
      return download_->state() != DownloadItem::CANCELLED;
    case ALWAYS_OPEN_TYPE:
#if defined(OS_WIN)
      return download_util::CanOpenDownload(download_);
#elif defined(OS_LINUX)
      // Need to implement dangerous download stuff: http://crbug.com/11780
      return false;
#endif
    case CANCEL:
      return download_->state() == DownloadItem::IN_PROGRESS;
    default:
      return id > 0 && id < MENU_LAST;
  }
}

void DownloadShelfContextMenu::ExecuteItemCommand(int id) {
  switch (id) {
    case SHOW_IN_FOLDER:
      download_->manager()->ShowDownloadInShell(download_);
      break;
    case OPEN_WHEN_COMPLETE:
#if defined(OS_WIN)
      download_util::OpenDownload(download_);
#else
      // TODO(port): port download_util
      NOTIMPLEMENTED();
#endif
      break;
    case ALWAYS_OPEN_TYPE: {
      const FilePath::StringType extension =
          file_util::GetFileExtensionFromPath(download_->full_path());
      download_->manager()->OpenFilesOfExtension(
          extension, !ItemIsChecked(ALWAYS_OPEN_TYPE));
      break;
    }
    case CANCEL:
      model_->CancelTask();
      break;
    default:
      NOTREACHED();
  }
}
<|endoftext|>


<commit_before>/*********************************************************************
** Author: Zach Colbert
** Date: 1 November 2017
** Description:
*********************************************************************/

// Pre-processing includes pre-requisite libraries for the functions below
#include <string>

// Make sure to include the header file where we declare the player class!
#include "Player.hpp"

/*********************************************************************
** Description: The default constructor for the Player class takes no arguments, and sets the player's name and stats to default values.

Default name: ""
Default stats: -1
*********************************************************************/

Player::Player()
{
    // Set player name to empty string
    setName("");

    // Set player stats to -1
    setPoints(-1);
    setRebounds(-1);
    setAssists(-1);
}

/*********************************************************************
** Description: This constructor for the Player class takes four arguments, and sets up a player object with name and stats based on those arguments.

** Usage: Player myPlayer(<name>, <points>, <rebounds>, <assists>);

** Example: Player player1(Zach, 20, 10, 0);
*********************************************************************/

Player::Player(std::string nameString, int pointValue, int reboundValue, int assistValue)
{
    // Set player name from argument
    setName(nameString);

    // Set player stats from arguments
    setPoints(pointValue);
    setRebounds(reboundValue);
    setAssists(assistValue);
}

/*********************************************************************
** Description: This function of the Player class takes no arguments, and returns the string "name" member variable of a called Player object.

** Usage: myPlayer.getName();
*********************************************************************/

std::string Player::getName()
{
    return name;
}

/*********************************************************************
** Description: This function of the Player class takes one argument, and modifies the integer "points" member variable of a called Player object.

** Usage: myPlayer.setPoints(<pointValue>);

** Example: myPlayer.setPoints(7);
*********************************************************************/

void Player::setPoints(int pointValue)
{
    points = pointValue;
}

/*********************************************************************
** Description: This function of the Player class takes no arguments, and returns the integer value of the "points" member variable of a called Player object.

** Usage: myPlayer.getPoints();
*********************************************************************/

int Player::getPoints()
{
    return points;
}

/*********************************************************************
** Description: This function of the Player class takes one argument, and modifies the integer "rebounds" member variable of a called Player object.

** Usage: myPlayer.setRebounds(<reboundValue>);

** Example: myPlayer.setRebounds(4);
*********************************************************************/

void Player::setRebounds(int reboundValue)
{
    rebounds = reboundValue;
}

/*********************************************************************
** Description: This function of the Player class takes no arguments, and returns the integer value of the "rebounds" member variable of a called Player object.

** Usage: myPlayer.getRebounds();
*********************************************************************/

int Player::getRebounds()
{
    return rebounds;
}

/*********************************************************************
** Description: This function of the Player class takes one argument, and modifies the integer "assists" member variable of a called Player object.

** Usage: myPlayer.setAssists(<assistValue>);

** Example: myPlayer.setAssists(10);
*********************************************************************/

void Player::setAssists(int assistValue)
{
    assists = assistValue;
}

/*********************************************************************
** Description: This function of the Player class takes no arguments, and returns the integer value of the "assists" member variable of a called Player object.

** Usage: myPlayer.getAssists();
*********************************************************************/

int Player::getAssists()
{
    return assists;
}

/*********************************************************************
** Description: This function of the Player class takes one Player object as an argument, and returns a boolean value. It compares the points stats of the called Player object and the argument Player object, and returns TRUE if the value of the called player's points is greater than the value of the argument player's points. In the converse case, it returns FALSE.

** Usage: myPlayer.hasMorePointsThan(<otherPlayer>);

** Example Input: player1.hasMorePointsThan(player2);

** Example Output: FALSE
*********************************************************************/

bool Player::hasMorePointsThan(Player argPlayer)
{
    return points > argPlayer.getPoints();
}
<commit_msg>Updated function descriptions<commit_after>/*********************************************************************
** Author: Zach Colbert
** Date: 1 November 2017
** Description:
*********************************************************************/

// Pre-processing includes pre-requisite libraries for the functions below
#include <string>

// Make sure to include the header file where we declare the player class!
#include "Player.hpp"

/*********************************************************************
** Description: The default constructor for the Player class takes no arguments, and sets the player's name and stats to default values.

Default name: ""
Default stats: -1
*********************************************************************/

Player::Player()
{
    // Set player name to empty string
    setName("");

    // Set player stats to -1
    setPoints(-1);
    setRebounds(-1);
    setAssists(-1);
}

/*********************************************************************
** Description: This constructor for the Player class takes four arguments, and sets up a player object with name and stats based on those arguments.

** Usage: Player myPlayer(<name>, <points>, <rebounds>, <assists>);

** Example: Player player1(Zach, 20, 10, 0);
*********************************************************************/

Player::Player(std::string nameString, int pointValue, int reboundValue, int assistValue)
{
    // Set player name from argument
    setName(nameString);

    // Set player stats from arguments
    setPoints(pointValue);
    setRebounds(reboundValue);
    setAssists(assistValue);
}

// Accessor function for the name attribute

std::string Player::getName()
{
    return name;
}

// Mutator function for the points attribute

void Player::setPoints(int pointValue)
{
    points = pointValue;
}

// Accessor function for the points attribute

int Player::getPoints()
{
    return points;
}

// Mutator function for the rebounds attribute

void Player::setRebounds(int reboundValue)
{
    rebounds = reboundValue;
}

// Accessor function for the rebounds attribute

int Player::getRebounds()
{
    return rebounds;
}

// Mutator function for the assists attribute

void Player::setAssists(int assistValue)
{
    assists = assistValue;
}

// Accessor function for the assists attribute

int Player::getAssists()
{
    return assists;
}

/*********************************************************************
** Description: This function of the Player class takes one Player object as an argument, and returns a boolean value. It compares the points stats of the called Player object and the argument Player object, and returns TRUE if the value of the called player's points is greater than the value of the argument player's points. In the converse case, it returns FALSE.

** Usage: myPlayer.hasMorePointsThan(<otherPlayer>);

** Example Input: player1.hasMorePointsThan(player2);

** Example Output: FALSE
*********************************************************************/

bool Player::hasMorePointsThan(Player argPlayer)
{
    return points > argPlayer.getPoints();
}
<|endoftext|>


<commit_before>#pragma ident "$Id$"

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

/**
   A simple GPS signal simulator. Based upon code from Johnathan York.

   See http://sglwiki/cgi-bin/twiki/view/SGL/SwRxSignalPathDesign for the
   derivation of the several of the values below.

   Needs to support the following modes to support receiver development:
 	carrier w/o noise
	carrier w noise
	C/A w/o noise
	C/A w noise
	C/A + nav + noise
	P + nav + noise
	P + C/A + nav + noise
	L1 + L2 P, C/A + nav + noise
*/

#include <math.h>
#include <complex>
#include <iostream>
#include <list>

#include "BasicFramework.hpp"
#include "CommandOption.hpp"
#include "StringUtils.hpp"
#include "icd_200_constants.hpp"

#include "SVSource.hpp"
#include "normal.hpp"
#include "IQStream.hpp"

using namespace gpstk;
using namespace std;

/* exp10() is a gnu specific extensions */
#ifndef exp10
#define exp10(x) (exp((x)*log((long double)10)))
#endif

class GpsSim : public BasicFramework
{
public:
   GpsSim() throw();

   bool initialize(int argc, char *argv[]) throw();

   // Base frequency of receiver (in Hz)
   const double RX_BASE_FREQ;

   // How many samples are taken in one base period
   const int RX_SAMPLE_RATE_MULTIPLIER;

   // The multipliers applied to the base frequency to get the local
   // oscilator for the mixers.
   const int RX_L1_LO_MULTIPLIER;
   const int RX_L2_LO_MULTIPLIER;

   // Number of local oscilators
   const int LO_COUNT;

   // The units of these are counts of the ADC
   double noise_amplitude, p_amplitude, ca_amplitude;

   // A gain to apply to the 'final' signal
   double gain;

   // number of seconds between samples
   double time_step;

   // One period is a tick of the RX_BASE_FREQ clock
   unsigned long periods_to_generate;

   bool codeOnly;

   list<SVSource*> sv_sources;

   vector<double> omega_lo;

   double freqErr;

   IQStream *output;

protected:
   virtual void process();
};

GpsSim::GpsSim() throw() :
   BasicFramework("gpsSim", "A simple simulation of a the GPS signal."),
   periods_to_generate(4096),
   LO_COUNT(2),
   RX_BASE_FREQ(1.0e6),
   RX_SAMPLE_RATE_MULTIPLIER(20),
   RX_L1_LO_MULTIPLIER(1575),
   RX_L2_LO_MULTIPLIER(1228),
   time_step(1.0/(RX_BASE_FREQ*RX_SAMPLE_RATE_MULTIPLIER)),
   p_amplitude(0.1250*M_SQRT2),
   ca_amplitude(0.1767*M_SQRT2),
   noise_amplitude(2.805),
   codeOnly(false),
   gain(1)
{}

bool GpsSim::initialize(int argc, char *argv[]) throw()
{
   CommandOptionWithAnyArg
      codeOpt('c', "code",
              "Generate the signal defined by the argument. ARG takes "
              "the form of code:carrier:prn:offset:doppler:nav. Code is either "
              "c, p, or cp. Carrier is either 1 or 2. Prn is an integer between 1 "
              "and 32. Offset is a number in microseconds. Doppler is a number "
              "in Hz. Nav is 0, c, p, or cp. For example, to generate C/A on L1 for "
              "PRN 15 with zero time-offset, zero doppler, a dummy nav signal "
              "on both C/A and P, then specify -c c:1:15:0:p.  This option "
              "may be repeated to simulate multiple signals.");

   CommandOptionNoArg
      codeOnlyOpt('\0', "code-only",
                  "Only generate the codes. No carrier, no hetrodyning.");

   CommandOptionWithAnyArg
      quantizationOpt('q', "quantization",
                      "What type of IQ stream; 1, 2 or f. The default is f.");

   CommandOptionWithAnyArg
      gainOpt('g', "gain",
              "Gain to apply to the if prior to digitization, in dB. Default is 0.");

   CommandOptionWithAnyArg
      noiseGainOpt('n', "noise",
                   "Specify the gain (in dB) for the receiver's noise. The "
                   "default is 0 dB");

   CommandOptionWithAnyArg
      freqErrOpt('f', "freq-err",
                 "Specify the frequency error on the local receiver's "
                 "oscilator, in ppm. The default is 0 ppm");

   CommandOptionWithAnyArg
      runTimeOpt('t', "run-time",
                 "How long (in ms) to run the simulation for. The default is 20 ms");

   CommandOptionWithAnyArg
      outputOpt('o', "output",
                 "Where to write the output. The default is stdout");

   if (!BasicFramework::initialize(argc,argv))
      return false;

   using namespace gpstk::StringUtils;

   char quantization='f';
   if (quantizationOpt.getCount())
      quantization = quantizationOpt.getValue()[0][0];

   switch (quantization)
   {
      case '1': output = new IQ1Stream(); break;
      case '2': output = new IQ2Stream(); break;
      case 'f':
      default:  output = new IQFloatStream(); break;
   }

   if (outputOpt.getCount())
   {
      output->open(outputOpt.getValue()[0].c_str(), ios::out);
   }
   else
   {
      using std::basic_ios;
      output->copyfmt(std::cout);
      output->clear(std::cout.rdstate());
      output->basic_ios<char>::rdbuf(std::cout.rdbuf());
      output->filename = "<stdout>";
   }
   if (debugLevel)
      cout << "Writing data to " << output->filename << endl;

   if (gainOpt.getCount())
   {
      double gainDb = StringUtils::asDouble(gainOpt.getValue()[0]);
      gain = exp10(gainDb/10);
      if (debugLevel)
         cout << "# Rx gain level: " << gainDb << " db ("
              << gain << ")" << endl;
   }

   if (noiseGainOpt.getCount())
   {
      double gain = StringUtils::asDouble(noiseGainOpt.getValue()[0]);
      noise_amplitude *= exp10(gain/10);
      if (debugLevel)
         cout << "# Noise level: " << gain << " db" << endl;
   }

   if (codeOnlyOpt.getCount())
      codeOnly = true;

   if (freqErrOpt.getCount())
      freqErr = StringUtils::asDouble(freqErrOpt.getValue()[0]) * 1e-6;
   else
      freqErr = 0;

   if (debugLevel)
      cout << "# Receiver frequency error: " << freqErr * 1e6 << " ppm" << endl;

   if (runTimeOpt.getCount())
   {
      double rt = asDouble(runTimeOpt.getValue()[0]);
      periods_to_generate = static_cast<long unsigned>(rt*RX_BASE_FREQ);
   }

   if (debugLevel)
      cout << "# Running for : " << periods_to_generate
           << " periods (" << 1e3 * periods_to_generate/RX_BASE_FREQ
           << " msec)" << endl;

   // Compute the local oscilator frequencies, units seem to be radians/sample
   omega_lo.resize(LO_COUNT);
   omega_lo[0] = 2.0*PI*RX_L1_LO_MULTIPLIER/RX_SAMPLE_RATE_MULTIPLIER;
   omega_lo[1] = 2.0*PI*RX_L2_LO_MULTIPLIER/RX_SAMPLE_RATE_MULTIPLIER;

   vector<double> lo(LO_COUNT);
   lo[0] = omega_lo[0]/time_step / 2 /PI;
   lo[1] = omega_lo[1]/time_step / 2 /PI;

   if (debugLevel)
      cout << "# LO 1: " << setw(7) << lo[0] * 1e-6<< " MHz"
           <<    "  2: " << setw(7) << lo[1] * 1e-6<< " MHz"
           <<  endl
           << "# IF 1: " << setw(7) << (L1_FREQ - lo[0]) * 1e-3<< " kHz"
           <<    "  2: " << setw(7) << (L2_FREQ - lo[1]) * 1e-3<< " kHz"
           <<  endl;

   for (int i=0; i < codeOpt.getCount(); i++)
   {
      string val=codeOpt.getValue()[i];
      const char delim(':');
      if (numWords(val, delim) != 6)
      {
         cout << "Error in code parameter:" << val << endl;
         exit(-1);
      }

      string code =   lowerCase(word(val, 0, delim));
      int    band =       asInt(word(val, 1, delim));
      int    prn =        asInt(word(val, 2, delim));
      double offset =  asDouble(word(val, 3, delim));
      double doppler = asDouble(word(val, 4, delim));
      string nav =    lowerCase(word(val, 5, delim));

      if (code.size() > 2 || nav.size() > 2 || band <1 || band > LO_COUNT ||
          prn < 1 || prn >32)
      {
         cout << "code:" << code << " band:" << band << " prn:" << prn
              << " offset:" << offset << " nav:" << nav << endl
              << "Error in specifying code. Ignoring this code." << endl;
         exit(-1);
      }

      // This is the number of P code chips in one sample. If this
      // is not around or less than 1/2, we have a problem
      double sampleRate = 1/(RX_SAMPLE_RATE_MULTIPLIER*RX_BASE_FREQ); //sec
      double chips_per_sample_base = gpstk::PY_CHIP_FREQ * sampleRate;

      switch(band)
      {
         case 1: doppler *= sampleRate / L1_MULT; break;
         case 2: doppler *= sampleRate / L2_MULT; break;
      }

      doppler *= 1-freqErr;
      chips_per_sample_base *= 1-freqErr;

      // Create and configure the SV source
      SVSource* src = new SVSource(prn, band);
      src->zchips_per_sample = chips_per_sample_base;
      src->doppler = doppler;
      src->ca_modulation = isLike(code, "c");
      src->p_modulation = isLike(code, "p");
      src->ca_nav = isLike(nav, "c") && src->ca_modulation;
      src->p_nav = isLike(nav, "p") && src->p_modulation;
      src->p_amplitude = p_amplitude;
      src->ca_amplitude = ca_amplitude;
      // offset needs to be provided to the SVSource in units of P chips
      src->slewZChipFraction(offset * gpstk::PY_CHIP_FREQ * 1e-6);

      if (codeOnlyOpt.getCount())
         src->code_only = true;

      if (debugLevel)
         src->dump(cout);

      sv_sources.push_back(src);
   }

   return true;
}

void GpsSim::process()
{
   // Used to accumulate up the samples
   vector<complex<float>> accum(LO_COUNT);

   // simulation time, in seconds
   double rx_time = 0;

   for(int period=0; period<periods_to_generate; ++period)
   {
      for(int sample=0; sample<RX_SAMPLE_RATE_MULTIPLIER; ++sample)
      {
         rx_time += time_step;

         // Clear out our accumulators
         for (int i=0; i < LO_COUNT; i++)
            accum[i] = (0,0);

         // Sum the signals from each SV
         list<SVSource*>::iterator i;
         for(i = sv_sources.begin(); i != sv_sources.end(); i++)
         {
            SVSource* src = *i;
            int band=src->band-1;
            accum[band] += src->getSample();
            src->incrementState();
         }

         // For each local oscilator frequency...
         for (int i=0; i<LO_COUNT; i++)
         {
            // Compute the local oscilator and the sample noise
            complex<double> lo = sincos(omega_lo[i] * sample);
            complex<double> noise(generate_normal_rv()*noise_amplitude,
                                  generate_normal_rv()*noise_amplitude);

            // Heterodyne the signals
            if (!codeOnly)
               accum[i] *= conj(lo);

            // and add the noise
            accum[i] += noise;

            // Apply receiver gain
            accum[i] *= gain;

            // And output the samples
            *output << accum[i];
         }
      }
   }
}

int main(int argc, char *argv[])
{
   try
   {
      GpsSim crap;
      if (!crap.initialize(argc, argv))
         exit(0);
      crap.run();
   }
   catch (gpstk::Exception &exc)
   { cerr << exc << endl; }
   catch (std::exception &exc)
   { cerr << "Caught std::exception " << exc.what() << endl; }
   catch (...)
   { cerr << "Caught unknown exception" << endl; }
}
<commit_msg>updating change to build on OS X as well<commit_after>#pragma ident "$Id$"

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

/**
   A simple GPS signal simulator. Based upon code from Johnathan York.

   See http://sglwiki/cgi-bin/twiki/view/SGL/SwRxSignalPathDesign for the
   derivation of the several of the values below.

   Needs to support the following modes to support receiver development:
 	carrier w/o noise
	carrier w noise
	C/A w/o noise
	C/A w noise
	C/A + nav + noise
	P + nav + noise
	P + C/A + nav + noise
	L1 + L2 P, C/A + nav + noise
*/

#include <math.h>
#include <complex>
#include <iostream>
#include <list>

#include "BasicFramework.hpp"
#include "CommandOption.hpp"
#include "StringUtils.hpp"
#include "icd_200_constants.hpp"

#include "SVSource.hpp"
#include "normal.hpp"
#include "IQStream.hpp"

using namespace gpstk;
using namespace std;

/* exp10() is a gnu specific extensions */
#ifndef exp10
#define exp10(x) (exp((x)*log((long double)10)))
#endif

class GpsSim : public BasicFramework
{
public:
   GpsSim() throw();

   bool initialize(int argc, char *argv[]) throw();

   // Base frequency of receiver (in Hz)
   const double RX_BASE_FREQ;

   // How many samples are taken in one base period
   const int RX_SAMPLE_RATE_MULTIPLIER;

   // The multipliers applied to the base frequency to get the local
   // oscilator for the mixers.
   const int RX_L1_LO_MULTIPLIER;
   const int RX_L2_LO_MULTIPLIER;

   // Number of local oscilators
   const int LO_COUNT;

   // The units of these are counts of the ADC
   double noise_amplitude, p_amplitude, ca_amplitude;

   // A gain to apply to the 'final' signal
   double gain;

   // number of seconds between samples
   double time_step;

   // One period is a tick of the RX_BASE_FREQ clock
   unsigned long periods_to_generate;

   bool codeOnly;

   list<SVSource*> sv_sources;

   vector<double> omega_lo;

   double freqErr;

   IQStream *output;

protected:
   virtual void process();
};

GpsSim::GpsSim() throw() :
   BasicFramework("gpsSim", "A simple simulation of a the GPS signal."),
   periods_to_generate(4096),
   LO_COUNT(2),
   RX_BASE_FREQ(1.0e6),
   RX_SAMPLE_RATE_MULTIPLIER(20),
   RX_L1_LO_MULTIPLIER(1575),
   RX_L2_LO_MULTIPLIER(1228),
   time_step(1.0/(RX_BASE_FREQ*RX_SAMPLE_RATE_MULTIPLIER)),
   p_amplitude(0.1250*M_SQRT2),
   ca_amplitude(0.1767*M_SQRT2),
   noise_amplitude(2.805),
   codeOnly(false),
   gain(1)
{}

bool GpsSim::initialize(int argc, char *argv[]) throw()
{
   CommandOptionWithAnyArg
      codeOpt('c', "code",
              "Generate the signal defined by the argument. ARG takes "
              "the form of code:carrier:prn:offset:doppler:nav. Code is either "
              "c, p, or cp. Carrier is either 1 or 2. Prn is an integer between 1 "
              "and 32. Offset is a number in microseconds. Doppler is a number "
              "in Hz. Nav is 0, c, p, or cp. For example, to generate C/A on L1 for "
              "PRN 15 with zero time-offset, zero doppler, a dummy nav signal "
              "on both C/A and P, then specify -c c:1:15:0:p.  This option "
              "may be repeated to simulate multiple signals.");

   CommandOptionNoArg
      codeOnlyOpt('\0', "code-only",
                  "Only generate the codes. No carrier, no hetrodyning.");

   CommandOptionWithAnyArg
      quantizationOpt('q', "quantization",
                      "What type of IQ stream; 1, 2 or f. The default is f.");

   CommandOptionWithAnyArg
      gainOpt('g', "gain",
              "Gain to apply to the if prior to digitization, in dB. Default is 0.");

   CommandOptionWithAnyArg
      noiseGainOpt('n', "noise",
                   "Specify the gain (in dB) for the receiver's noise. The "
                   "default is 0 dB");

   CommandOptionWithAnyArg
      freqErrOpt('f', "freq-err",
                 "Specify the frequency error on the local receiver's "
                 "oscilator, in ppm. The default is 0 ppm");

   CommandOptionWithAnyArg
      runTimeOpt('t', "run-time",
                 "How long (in ms) to run the simulation for. The default is 20 ms");

   CommandOptionWithAnyArg
      outputOpt('o', "output",
                 "Where to write the output. The default is stdout");

   if (!BasicFramework::initialize(argc,argv))
      return false;

   using namespace gpstk::StringUtils;

   char quantization='f';
   if (quantizationOpt.getCount())
      quantization = quantizationOpt.getValue()[0][0];

   switch (quantization)
   {
      case '1': output = new IQ1Stream(); break;
      case '2': output = new IQ2Stream(); break;
      case 'f':
      default:  output = new IQFloatStream(); break;
   }

   if (outputOpt.getCount())
   {
      output->open(outputOpt.getValue()[0].c_str(), ios::out);
   }
   else
   {
      using std::basic_ios;
      output->copyfmt(std::cout);
      output->clear(std::cout.rdstate());
      output->basic_ios<char>::rdbuf(std::cout.rdbuf());
      output->filename = "<stdout>";
   }
   if (debugLevel)
      cout << "Writing data to " << output->filename << endl;

   if (gainOpt.getCount())
   {
      double gainDb = StringUtils::asDouble(gainOpt.getValue()[0]);
      gain = exp10(gainDb/10);
      if (debugLevel)
         cout << "# Rx gain level: " << gainDb << " db ("
              << gain << ")" << endl;
   }

   if (noiseGainOpt.getCount())
   {
      double gain = StringUtils::asDouble(noiseGainOpt.getValue()[0]);
      noise_amplitude *= exp10(gain/10);
      if (debugLevel)
         cout << "# Noise level: " << gain << " db" << endl;
   }

   if (codeOnlyOpt.getCount())
      codeOnly = true;

   if (freqErrOpt.getCount())
      freqErr = StringUtils::asDouble(freqErrOpt.getValue()[0]) * 1e-6;
   else
      freqErr = 0;

   if (debugLevel)
      cout << "# Receiver frequency error: " << freqErr * 1e6 << " ppm" << endl;

   if (runTimeOpt.getCount())
   {
      double rt = asDouble(runTimeOpt.getValue()[0]);
      periods_to_generate = static_cast<long unsigned>(rt*RX_BASE_FREQ);
   }

   if (debugLevel)
      cout << "# Running for : " << periods_to_generate
           << " periods (" << 1e3 * periods_to_generate/RX_BASE_FREQ
           << " msec)" << endl;

   // Compute the local oscilator frequencies, units seem to be radians/sample
   omega_lo.resize(LO_COUNT);
   omega_lo[0] = 2.0*PI*RX_L1_LO_MULTIPLIER/RX_SAMPLE_RATE_MULTIPLIER;
   omega_lo[1] = 2.0*PI*RX_L2_LO_MULTIPLIER/RX_SAMPLE_RATE_MULTIPLIER;

   vector<double> lo(LO_COUNT);
   lo[0] = omega_lo[0]/time_step / 2 /PI;
   lo[1] = omega_lo[1]/time_step / 2 /PI;

   if (debugLevel)
      cout << "# LO 1: " << setw(7) << lo[0] * 1e-6<< " MHz"
           <<    "  2: " << setw(7) << lo[1] * 1e-6<< " MHz"
           <<  endl
           << "# IF 1: " << setw(7) << (L1_FREQ - lo[0]) * 1e-3<< " kHz"
           <<    "  2: " << setw(7) << (L2_FREQ - lo[1]) * 1e-3<< " kHz"
           <<  endl;

   for (int i=0; i < codeOpt.getCount(); i++)
   {
      string val=codeOpt.getValue()[i];
      const char delim(':');
      if (numWords(val, delim) != 6)
      {
         cout << "Error in code parameter:" << val << endl;
         exit(-1);
      }

      string code =   lowerCase(word(val, 0, delim));
      int    band =       asInt(word(val, 1, delim));
      int    prn =        asInt(word(val, 2, delim));
      double offset =  asDouble(word(val, 3, delim));
      double doppler = asDouble(word(val, 4, delim));
      string nav =    lowerCase(word(val, 5, delim));

      if (code.size() > 2 || nav.size() > 2 || band <1 || band > LO_COUNT ||
          prn < 1 || prn >32)
      {
         cout << "code:" << code << " band:" << band << " prn:" << prn
              << " offset:" << offset << " nav:" << nav << endl
              << "Error in specifying code. Ignoring this code." << endl;
         exit(-1);
      }

      // This is the number of P code chips in one sample. If this
      // is not around or less than 1/2, we have a problem
      double sampleRate = 1/(RX_SAMPLE_RATE_MULTIPLIER*RX_BASE_FREQ); //sec
      double chips_per_sample_base = gpstk::PY_CHIP_FREQ * sampleRate;

      switch(band)
      {
         case 1: doppler *= sampleRate / L1_MULT; break;
         case 2: doppler *= sampleRate / L2_MULT; break;
      }

      doppler *= 1-freqErr;
      chips_per_sample_base *= 1-freqErr;

      // Create and configure the SV source
      SVSource* src = new SVSource(prn, band);
      src->zchips_per_sample = chips_per_sample_base;
      src->doppler = doppler;
      src->ca_modulation = isLike(code, "c");
      src->p_modulation = isLike(code, "p");
      src->ca_nav = isLike(nav, "c") && src->ca_modulation;
      src->p_nav = isLike(nav, "p") && src->p_modulation;
      src->p_amplitude = p_amplitude;
      src->ca_amplitude = ca_amplitude;
      // offset needs to be provided to the SVSource in units of P chips
      src->slewZChipFraction(offset * gpstk::PY_CHIP_FREQ * 1e-6);

      if (codeOnlyOpt.getCount())
         src->code_only = true;

      if (debugLevel)
         src->dump(cout);

      sv_sources.push_back(src);
   }

   return true;
}

void GpsSim::process()
{
   // Used to accumulate up the samples
   vector< complex<float> > accum(LO_COUNT);

   // simulation time, in seconds
   double rx_time = 0;

   for(int period=0; period<periods_to_generate; ++period)
   {
      for(int sample=0; sample<RX_SAMPLE_RATE_MULTIPLIER; ++sample)
      {
         rx_time += time_step;

         // Clear out our accumulators
         for (int i=0; i < LO_COUNT; i++)
            accum[i] = (0,0);

         // Sum the signals from each SV
         list<SVSource*>::iterator i;
         for(i = sv_sources.begin(); i != sv_sources.end(); i++)
         {
            SVSource* src = *i;
            int band=src->band-1;
            accum[band] += src->getSample();
            src->incrementState();
         }

         // For each local oscilator frequency...
         for (int i=0; i<LO_COUNT; i++)
         {
            // Compute the local oscilator and the sample noise
            complex<double> lo = sincos(omega_lo[i] * sample);
            complex<double> noise(generate_normal_rv()*noise_amplitude,
                                  generate_normal_rv()*noise_amplitude);

            // Heterodyne the signals
            if (!codeOnly)
               accum[i] *= conj(lo);

            // and add the noise
            accum[i] += noise;

            // Apply receiver gain
            accum[i] *= gain;

            // And output the samples
            *output << accum[i];
         }
      }
   }
}

int main(int argc, char *argv[])
{
   try
   {
      GpsSim crap;
      if (!crap.initialize(argc, argv))
         exit(0);
      crap.run();
   }
   catch (gpstk::Exception &exc)
   { cerr << exc << endl; }
   catch (std::exception &exc)
   { cerr << "Caught std::exception " << exc.what() << endl; }
   catch (...)
   { cerr << "Caught unknown exception" << endl; }
}
<|endoftext|>


<commit_before>/* Copyright (C) 2003 MySQL AB

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

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

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

#include <NDBT.hpp>
#include <NDBT_Test.hpp>
#include <HugoTransactions.hpp>
#include <UtilTransactions.hpp>
#include <random.h>
#include <getarg.h>

struct Parameter {
  const char * name;
  unsigned value;
  unsigned min;
  unsigned max;
};

#define P_OPER    0
#define P_RANGE   1
#define P_ROWS    2
#define P_LOOPS   3
#define P_CREATE  4
#define P_LOAD    5

#define P_MAX 6

/**
 * operation
 * 0 - serial pk
 * 1 - batch pk
 * 2 - serial uniq
 * 3 - batch uniq
 * 4 - index eq
 * 5 - range scan
 * 6 - ordered range scan
 * 7 - interpreted scan
 */
static const char * g_ops[] = {
  "serial pk",
  "batch pk",
  "serial uniq index access",
  "batch uniq index access",
  "index eq-bound",
  "index range",
  "index ordered",
  "interpreted scan"
};

#define P_OP_TYPES 8
static Uint64 g_times[P_OP_TYPES];

static
Parameter
g_paramters[] = {
  { "operation",   0, 0, 6 }, // 0
  { "range",    1000, 1, ~0 },// 1 no of rows to read
  { "size",  1000000, 1, ~0 },// 2 rows in tables
  { "iterations",  3, 1, ~0 },// 3
  { "create_drop", 0, 0, 1 }, // 4
  { "data",        0, 0, 1 }  // 5
};

static Ndb* g_ndb = 0;
static const NdbDictionary::Table * g_tab;
static const NdbDictionary::Index * g_i_unique;
static const NdbDictionary::Index * g_i_ordered;
static char g_table[256];
static char g_unique[256];
static char g_ordered[256];
static char g_buffer[2*1024*1024];

int create_table();
int load_table();
int run_read();
int clear_table();
int drop_table();
void print_result();

int
main(int argc, const char** argv){
  int verbose = 1;
  int optind = 0;

  struct getargs args[1+P_MAX] = {
    { "verbose", 'v', arg_flag, &verbose, "Print verbose status", "verbose" }
  };
  const int num_args = 1 + P_MAX;
  for(int i = 0; i<P_MAX; i++){
    args[i+1].long_name = g_paramters[i].name;
    args[i+1].short_name = * g_paramters[i].name;
    args[i+1].type = arg_integer;
    args[i+1].value = &g_paramters[i].value;
    BaseString tmp;
    tmp.assfmt("min: %d max: %d", g_paramters[i].min, g_paramters[i].max);
    args[i+1].help = strdup(tmp.c_str());
    args[i+1].arg_help = 0;
  }

  if(getarg(args, num_args, argc, argv, &optind)) {
    arg_printusage(args, num_args, argv[0], "tabname1 tabname2 ...");
    return NDBT_WRONGARGS;
  }

  myRandom48Init(NdbTick_CurrentMillisecond());

  g_ndb = new Ndb("TEST_DB");
  if(g_ndb->init() != 0){
    g_err << "init() failed" << endl;
    goto error;
  }
  if(g_ndb->waitUntilReady() != 0){
    g_err << "Wait until ready failed" << endl;
    goto error;
  }
  for(int i = optind; i<argc; i++){
    const char * T = argv[i];
    g_info << "Testing " << T << endl;
    snprintf(g_table, sizeof(g_table), T);
    snprintf(g_ordered, sizeof(g_ordered), "IDX_O_%s", T);
    snprintf(g_unique, sizeof(g_unique), "IDX_U_%s", T);
    if(create_table())
      goto error;
    if(load_table())
      goto error;
    for(int l = 0; l<g_paramters[P_LOOPS].value; l++){
      for(int j = 0; j<P_OP_TYPES; j++){
	g_paramters[P_OPER].value = j;
	if(run_read())
	  goto error;
      }
    }
    print_result();
  }

  if(g_ndb) delete g_ndb;
  return NDBT_OK;
error:
  if(g_ndb) delete g_ndb;
  return NDBT_FAILED;
}

int
create_table(){
  NdbDictionary::Dictionary* dict = g_ndb->getDictionary();
  assert(dict);
  if(g_paramters[P_CREATE].value){
    const NdbDictionary::Table * pTab = NDBT_Tables::getTable(g_table);
    assert(pTab);
    NdbDictionary::Table copy = * pTab;
    copy.setLogging(false);
    if(dict->createTable(copy) != 0){
      g_err << "Failed to create table: " << g_table << endl;
      return -1;
    }

    NdbDictionary::Index x(g_ordered);
    x.setTable(g_table);
    x.setType(NdbDictionary::Index::OrderedIndex);
    x.setLogging(false);
    for (unsigned k = 0; k < copy.getNoOfColumns(); k++){
      if(copy.getColumn(k)->getPrimaryKey()){
	x.addColumn(copy.getColumn(k)->getName());
      }
    }

    if(dict->createIndex(x) != 0){
      g_err << "Failed to create index: " << endl;
      return -1;
    }

    x.setName(g_unique);
    x.setType(NdbDictionary::Index::UniqueHashIndex);
    if(dict->createIndex(x) != 0){
      g_err << "Failed to create index: " << endl;
      return -1;
    }
  }
  g_tab = dict->getTable(g_table);
  g_i_unique = dict->getIndex(g_unique, g_table);
  g_i_ordered = dict->getIndex(g_ordered, g_table);
  assert(g_tab);
  assert(g_i_unique);
  assert(g_i_ordered);
  return 0;
}

int
drop_table(){
  if(!g_paramters[P_CREATE].value)
    return 0;
  if(g_ndb->getDictionary()->dropTable(g_tab->getName()) != 0){
    g_err << "Failed to drop table: " << g_tab->getName() << endl;
    return -1;
  }
  g_tab = 0;
  return 0;
}

int
load_table(){
  if(!g_paramters[P_LOAD].value)
    return 0;

  int rows = g_paramters[P_ROWS].value;
  HugoTransactions hugoTrans(* g_tab);
  if (hugoTrans.loadTable(g_ndb, rows)){
    g_err.println("Failed to load %s with %d rows", g_tab->getName(), rows);
    return -1;
  }
  return 0;
}

int
clear_table(){
  if(!g_paramters[P_LOAD].value)
    return 0;
  int rows = g_paramters[P_ROWS].value;

  UtilTransactions utilTrans(* g_tab);
  if (utilTrans.clearTable(g_ndb,  rows) != 0){
    g_err.println("Failed to clear table %s", g_tab->getName());
    return -1;
  }
  return 0;
}

inline
void err(NdbError e){
  ndbout << e << endl;
}

int
run_read(){
  int iter = g_paramters[P_LOOPS].value;
  NDB_TICKS start1, stop;
  int sum_time= 0;

  const Uint32 rows = g_paramters[P_ROWS].value;
  const Uint32 range = g_paramters[P_RANGE].value;

  start1 = NdbTick_CurrentMillisecond();
  NdbConnection * pTrans = g_ndb->startTransaction();
  if(!pTrans){
    g_err << "Failed to start transaction" << endl;
    err(g_ndb->getNdbError());
    return -1;
  }

  NdbOperation * pOp;
  NdbScanOperation * pSp;
  NdbIndexOperation * pUp;
  NdbIndexScanOperation * pIp;
  NdbResultSet * rs = (NdbResultSet*)~0;

  Uint32 start_row = rand() % (rows - range);
  Uint32 stop_row = start_row + range;

  /**
   * 0 - serial pk
   * 1 - batch pk
   * 2 - serial uniq
   * 3 - batch uniq
   * 4 - index eq
   * 5 - range scan
   * 6 - interpreted scan
   */
  int check = 0;
  void* res = (void*)~0;
  const Uint32 pk = 0;
  Uint32 cnt = 0;
  for(; start_row < stop_row; start_row++){
    switch(g_paramters[P_OPER].value){
    case 0:
      pOp = pTrans->getNdbOperation(g_table);
      check = pOp->readTuple();
      check = pOp->equal(pk, start_row);
      break;
    case 1:
      for(; start_row<stop_row; start_row++){
	pOp = pTrans->getNdbOperation(g_table);
	check = pOp->readTuple();
	check = pOp->equal(pk, start_row);
	for(int j = 0; j<g_tab->getNoOfColumns(); j++){
	  res = pOp->getValue(j);
	  assert(res);
	}
      }
      break;
    case 2:
      pOp = pTrans->getNdbIndexOperation(g_unique, g_table);
      check = pOp->readTuple();
      check = pOp->equal(pk, start_row);
      break;
    case 3:
      for(; start_row<stop_row; start_row++){
	pOp = pTrans->getNdbIndexOperation(g_unique, g_table);
	check = pOp->readTuple();
	check = pOp->equal(pk, start_row);
	for(int j = 0; j<g_tab->getNoOfColumns(); j++){
	  res = pOp->getValue(j);
	  assert(res);
	}
      }
      break;
    case 4:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundEQ, &start_row);
      break;
    case 5:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
      start_row = stop_row;
      break;
    case 6:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0, true);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
      start_row = stop_row;
      break;
    case 7:
      pOp = pSp = pTrans->getNdbScanOperation(g_table);
      rs = pSp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      NdbScanFilter filter(pOp) ;
      filter.begin(NdbScanFilter::AND);
      filter.ge(pk, start_row);
      filter.lt(pk, stop_row);
      filter.end();
      start_row = stop_row;
      break;
    }

    assert(res);
    if(check != 0){
      ndbout << pOp->getNdbError() << endl;
      ndbout << pTrans->getNdbError() << endl;
    }
    assert(check == 0);
    assert(rs);

    for(int j = 0; j<g_tab->getNoOfColumns(); j++){
      res = pOp->getValue(j);
      assert(res);
    }

    check = pTrans->execute(NoCommit);
    if(check != 0){
      ndbout << pTrans->getNdbError() << endl;
    }
    assert(check == 0);
    if(g_paramters[P_OPER].value >= 4){
      while((check = rs->nextResult(true)) == 0){
	cnt++;
      }

      if(check == -1){
	err(pTrans->getNdbError());
	return -1;
      }
      assert(check == 1);
      rs->close();
    }
  }
  assert(g_paramters[P_OPER].value < 4 || (cnt == range));

  pTrans->close();

  stop = NdbTick_CurrentMillisecond();
  g_times[g_paramters[P_OPER].value] += (stop - start1);
  return 0;
}

void
print_result(){
  for(int i = 0; i<P_OP_TYPES; i++){
    g_err.println("%s avg: %u us/row", g_ops[i],
		  (1000*g_times[i])/g_paramters[P_RANGE].value);
  }
}
<commit_msg>testReadPerf  Divide by loops aswell<commit_after>/* Copyright (C) 2003 MySQL AB

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

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

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

#include <NDBT.hpp>
#include <NDBT_Test.hpp>
#include <HugoTransactions.hpp>
#include <UtilTransactions.hpp>
#include <random.h>
#include <getarg.h>

struct Parameter {
  const char * name;
  unsigned value;
  unsigned min;
  unsigned max;
};

#define P_OPER    0
#define P_RANGE   1
#define P_ROWS    2
#define P_LOOPS   3
#define P_CREATE  4
#define P_LOAD    5

#define P_MAX 6

/**
 * operation
 * 0 - serial pk
 * 1 - batch pk
 * 2 - serial uniq
 * 3 - batch uniq
 * 4 - index eq
 * 5 - range scan
 * 6 - ordered range scan
 * 7 - interpreted scan
 */
static const char * g_ops[] = {
  "serial pk",
  "batch pk",
  "serial uniq index access",
  "batch uniq index access",
  "index eq-bound",
  "index range",
  "index ordered",
  "interpreted scan"
};

#define P_OP_TYPES 8
static Uint64 g_times[P_OP_TYPES];

static
Parameter
g_paramters[] = {
  { "operation",   0, 0, 6 }, // 0
  { "range",    1000, 1, ~0 },// 1 no of rows to read
  { "size",  1000000, 1, ~0 },// 2 rows in tables
  { "iterations",  3, 1, ~0 },// 3
  { "create_drop", 0, 0, 1 }, // 4
  { "data",        0, 0, 1 }  // 5
};

static Ndb* g_ndb = 0;
static const NdbDictionary::Table * g_tab;
static const NdbDictionary::Index * g_i_unique;
static const NdbDictionary::Index * g_i_ordered;
static char g_table[256];
static char g_unique[256];
static char g_ordered[256];
static char g_buffer[2*1024*1024];

int create_table();
int load_table();
int run_read();
int clear_table();
int drop_table();
void print_result();

int
main(int argc, const char** argv){
  int verbose = 1;
  int optind = 0;

  struct getargs args[1+P_MAX] = {
    { "verbose", 'v', arg_flag, &verbose, "Print verbose status", "verbose" }
  };
  const int num_args = 1 + P_MAX;
  for(int i = 0; i<P_MAX; i++){
    args[i+1].long_name = g_paramters[i].name;
    args[i+1].short_name = * g_paramters[i].name;
    args[i+1].type = arg_integer;
    args[i+1].value = &g_paramters[i].value;
    BaseString tmp;
    tmp.assfmt("min: %d max: %d", g_paramters[i].min, g_paramters[i].max);
    args[i+1].help = strdup(tmp.c_str());
    args[i+1].arg_help = 0;
  }

  if(getarg(args, num_args, argc, argv, &optind)) {
    arg_printusage(args, num_args, argv[0], "tabname1 tabname2 ...");
    return NDBT_WRONGARGS;
  }

  myRandom48Init(NdbTick_CurrentMillisecond());

  g_ndb = new Ndb("TEST_DB");
  if(g_ndb->init() != 0){
    g_err << "init() failed" << endl;
    goto error;
  }
  if(g_ndb->waitUntilReady() != 0){
    g_err << "Wait until ready failed" << endl;
    goto error;
  }
  for(int i = optind; i<argc; i++){
    const char * T = argv[i];
    g_info << "Testing " << T << endl;
    snprintf(g_table, sizeof(g_table), T);
    snprintf(g_ordered, sizeof(g_ordered), "IDX_O_%s", T);
    snprintf(g_unique, sizeof(g_unique), "IDX_U_%s", T);
    if(create_table())
      goto error;
    if(load_table())
      goto error;
    for(int l = 0; l<g_paramters[P_LOOPS].value; l++){
      for(int j = 0; j<P_OP_TYPES; j++){
	g_paramters[P_OPER].value = j;
	if(run_read())
	  goto error;
      }
    }
    print_result();
  }

  if(g_ndb) delete g_ndb;
  return NDBT_OK;
error:
  if(g_ndb) delete g_ndb;
  return NDBT_FAILED;
}

int
create_table(){
  NdbDictionary::Dictionary* dict = g_ndb->getDictionary();
  assert(dict);
  if(g_paramters[P_CREATE].value){
    const NdbDictionary::Table * pTab = NDBT_Tables::getTable(g_table);
    assert(pTab);
    NdbDictionary::Table copy = * pTab;
    copy.setLogging(false);
    if(dict->createTable(copy) != 0){
      g_err << "Failed to create table: " << g_table << endl;
      return -1;
    }

    NdbDictionary::Index x(g_ordered);
    x.setTable(g_table);
    x.setType(NdbDictionary::Index::OrderedIndex);
    x.setLogging(false);
    for (unsigned k = 0; k < copy.getNoOfColumns(); k++){
      if(copy.getColumn(k)->getPrimaryKey()){
	x.addColumn(copy.getColumn(k)->getName());
      }
    }

    if(dict->createIndex(x) != 0){
      g_err << "Failed to create index: " << endl;
      return -1;
    }

    x.setName(g_unique);
    x.setType(NdbDictionary::Index::UniqueHashIndex);
    if(dict->createIndex(x) != 0){
      g_err << "Failed to create index: " << endl;
      return -1;
    }
  }
  g_tab = dict->getTable(g_table);
  g_i_unique = dict->getIndex(g_unique, g_table);
  g_i_ordered = dict->getIndex(g_ordered, g_table);
  assert(g_tab);
  assert(g_i_unique);
  assert(g_i_ordered);
  return 0;
}

int
drop_table(){
  if(!g_paramters[P_CREATE].value)
    return 0;
  if(g_ndb->getDictionary()->dropTable(g_tab->getName()) != 0){
    g_err << "Failed to drop table: " << g_tab->getName() << endl;
    return -1;
  }
  g_tab = 0;
  return 0;
}

int
load_table(){
  if(!g_paramters[P_LOAD].value)
    return 0;

  int rows = g_paramters[P_ROWS].value;
  HugoTransactions hugoTrans(* g_tab);
  if (hugoTrans.loadTable(g_ndb, rows)){
    g_err.println("Failed to load %s with %d rows", g_tab->getName(), rows);
    return -1;
  }
  return 0;
}

int
clear_table(){
  if(!g_paramters[P_LOAD].value)
    return 0;
  int rows = g_paramters[P_ROWS].value;

  UtilTransactions utilTrans(* g_tab);
  if (utilTrans.clearTable(g_ndb,  rows) != 0){
    g_err.println("Failed to clear table %s", g_tab->getName());
    return -1;
  }
  return 0;
}

inline
void err(NdbError e){
  ndbout << e << endl;
}

int
run_read(){
  int iter = g_paramters[P_LOOPS].value;
  NDB_TICKS start1, stop;
  int sum_time= 0;

  const Uint32 rows = g_paramters[P_ROWS].value;
  const Uint32 range = g_paramters[P_RANGE].value;

  start1 = NdbTick_CurrentMillisecond();
  NdbConnection * pTrans = g_ndb->startTransaction();
  if(!pTrans){
    g_err << "Failed to start transaction" << endl;
    err(g_ndb->getNdbError());
    return -1;
  }

  NdbOperation * pOp;
  NdbScanOperation * pSp;
  NdbIndexOperation * pUp;
  NdbIndexScanOperation * pIp;
  NdbResultSet * rs = (NdbResultSet*)~0;

  Uint32 start_row = rand() % (rows - range);
  Uint32 stop_row = start_row + range;

  /**
   * 0 - serial pk
   * 1 - batch pk
   * 2 - serial uniq
   * 3 - batch uniq
   * 4 - index eq
   * 5 - range scan
   * 6 - interpreted scan
   */
  int check = 0;
  void* res = (void*)~0;
  const Uint32 pk = 0;
  Uint32 cnt = 0;
  for(; start_row < stop_row; start_row++){
    switch(g_paramters[P_OPER].value){
    case 0:
      pOp = pTrans->getNdbOperation(g_table);
      check = pOp->readTuple();
      check = pOp->equal(pk, start_row);
      break;
    case 1:
      for(; start_row<stop_row; start_row++){
	pOp = pTrans->getNdbOperation(g_table);
	check = pOp->readTuple();
	check = pOp->equal(pk, start_row);
	for(int j = 0; j<g_tab->getNoOfColumns(); j++){
	  res = pOp->getValue(j);
	  assert(res);
	}
      }
      break;
    case 2:
      pOp = pTrans->getNdbIndexOperation(g_unique, g_table);
      check = pOp->readTuple();
      check = pOp->equal(pk, start_row);
      break;
    case 3:
      for(; start_row<stop_row; start_row++){
	pOp = pTrans->getNdbIndexOperation(g_unique, g_table);
	check = pOp->readTuple();
	check = pOp->equal(pk, start_row);
	for(int j = 0; j<g_tab->getNoOfColumns(); j++){
	  res = pOp->getValue(j);
	  assert(res);
	}
      }
      break;
    case 4:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundEQ, &start_row);
      break;
    case 5:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
      start_row = stop_row;
      break;
    case 6:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0, true);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
      start_row = stop_row;
      break;
    case 7:
      pOp = pSp = pTrans->getNdbScanOperation(g_table);
      rs = pSp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      NdbScanFilter filter(pOp) ;
      filter.begin(NdbScanFilter::AND);
      filter.ge(pk, start_row);
      filter.lt(pk, stop_row);
      filter.end();
      start_row = stop_row;
      break;
    }

    assert(res);
    if(check != 0){
      ndbout << pOp->getNdbError() << endl;
      ndbout << pTrans->getNdbError() << endl;
    }
    assert(check == 0);
    assert(rs);

    for(int j = 0; j<g_tab->getNoOfColumns(); j++){
      res = pOp->getValue(j);
      assert(res);
    }

    check = pTrans->execute(NoCommit);
    if(check != 0){
      ndbout << pTrans->getNdbError() << endl;
    }
    assert(check == 0);
    if(g_paramters[P_OPER].value >= 4){
      while((check = rs->nextResult(true)) == 0){
	cnt++;
      }

      if(check == -1){
	err(pTrans->getNdbError());
	return -1;
      }
      assert(check == 1);
      rs->close();
    }
  }
  assert(g_paramters[P_OPER].value < 4 || (cnt == range));

  pTrans->close();

  stop = NdbTick_CurrentMillisecond();
  g_times[g_paramters[P_OPER].value] += (stop - start1);
  return 0;
}

void
print_result(){
  for(int i = 0; i<P_OP_TYPES; i++){
    g_err.println("%s avg: %u us/row", g_ops[i],
		  (1000*g_times[i])/(g_paramters[P_RANGE].value*g_paramters[P_LOOPS].value));
  }
}
<|endoftext|>