<commit_before>/*
 * Copyright (c) 2004 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders 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
 * This code loads the linux kernel, console, pal and patches certain
 * functions.  The symbol tables are loaded so that traces can show
 * the executing function and we can skip functions. Various delay
 * loops are skipped and their final values manually computed to speed
 * up boot time.
 */

#include "base/trace.hh"
#include "cpu/exec_context.hh"
#include "cpu/base_cpu.hh"
#include "kern/linux/linux_events.hh"
#include "kern/linux/linux_system.hh"
#include "kern/system_events.hh"
#include "mem/functional_mem/memory_control.hh"
#include "mem/functional_mem/physical_memory.hh"
#include "sim/builder.hh"
#include "dev/platform.hh"
#include "targetarch/isa_traits.hh"
#include "targetarch/vtophys.hh"
#include "sim/debug.hh"

extern SymbolTable *debugSymbolTable;

using namespace std;

LinuxSystem::LinuxSystem(Params *p)
    : System(p)
{
    Addr addr = 0;

    /**
     * find the address of the est_cycle_freq variable and insert it
     * so we don't through the lengthly process of trying to
     * calculated it by using the PIT, RTC, etc.
     */
    if (kernelSymtab->findAddress("est_cycle_freq", addr)) {
        Addr paddr = vtophys(physmem, addr);
        uint8_t *est_cycle_frequency =
            physmem->dma_addr(paddr, sizeof(uint64_t));

        if (est_cycle_frequency)
            *(uint64_t *)est_cycle_frequency = htoa(ticksPerSecond);
    }

    /**
     * Since we aren't using a bootloader, we have to copy the kernel arguments
     * directly into the kernels memory.
     */
    {
        Addr paddr = vtophys(physmem, PARAM_ADDR);
        char *commandline = (char*)physmem->dma_addr(paddr, sizeof(uint64_t));
        if (commandline)
            strcpy(commandline, params->boot_osflags.c_str());
    }

    /**
     * EV5 only supports 127 ASNs so we are going to tell the kernel that the
     * paritiuclar EV6 we have only supports 127 asns.
     * @todo At some point we should change ev5.hh and the palcode to support
     * 255 ASNs.
     */
    if (kernelSymtab->findAddress("dp264_mv", addr)) {
        Addr paddr = vtophys(physmem, addr);
        char *dp264_mv = (char *)physmem->dma_addr(paddr, sizeof(uint64_t));

        if (dp264_mv) {
            *(uint32_t*)(dp264_mv+0x18) = htoa((uint32_t)127);
        } else
            panic("could not translate dp264_mv addr\n");

    } else
        panic("could not find dp264_mv\n");

#ifdef DEBUG
    kernelPanicEvent = new BreakPCEvent(&pcEventQueue, "kernel panic");
    if (kernelSymtab->findAddress("panic", addr))
        kernelPanicEvent->schedule(addr);
    else
        panic("could not find kernel symbol \'panic\'");
#endif

    /**
     * Any time ide_delay_50ms, calibarte_delay or
     * determine_cpu_caches is called just skip the
     * function. Currently determine_cpu_caches only is used put
     * information in proc, however if that changes in the future we
     * will have to fill in the cache size variables appropriately.
     */
    skipIdeDelay50msEvent = new SkipFuncEvent(&pcEventQueue, "ide_delay_50ms");
    if (kernelSymtab->findAddress("ide_delay_50ms", addr))
        skipIdeDelay50msEvent->schedule(addr+sizeof(MachInst));

    skipDelayLoopEvent = new LinuxSkipDelayLoopEvent(&pcEventQueue,
                                                     "calibrate_delay");
    if (kernelSymtab->findAddress("calibrate_delay", addr))
        skipDelayLoopEvent->schedule(addr+sizeof(MachInst));

    skipCacheProbeEvent = new SkipFuncEvent(&pcEventQueue,
                                            "determine_cpu_caches");
    if (kernelSymtab->findAddress("determine_cpu_caches", addr))
        skipCacheProbeEvent->schedule(addr+sizeof(MachInst));

    debugPrintkEvent = new DebugPrintkEvent(&pcEventQueue, "dprintk");
    if (kernelSymtab->findAddress("dprintk", addr))
        debugPrintkEvent->schedule(addr+8);

    idleStartEvent = new IdleStartEvent(&pcEventQueue, "cpu_idle", this);
    if (kernelSymtab->findAddress("cpu_idle", addr))
        idleStartEvent->schedule(addr);

    printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo");
    if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread))
        printThreadEvent->schedule(addr + sizeof(MachInst) * 6);

    intStartEvent = new InterruptStartEvent(&pcEventQueue, "intStartEvent");

    if (params->bin_int) {
        if (palSymtab->findAddress("sys_int_21", addr))
            intStartEvent->schedule(addr + sizeof(MachInst) * 2);
        else
            panic("could not find symbol: sys_int_21\n");

        intEndEvent = new InterruptEndEvent(&pcEventQueue, "intEndEvent");
        if (palSymtab->findAddress("rti_to_kern", addr))
            intEndEvent->schedule(addr) ;
        else
            panic("could not find symbol: rti_to_kern\n");

        intEndEvent2 = new InterruptEndEvent(&pcEventQueue, "intEndEvent2");
        if (palSymtab->findAddress("rti_to_user", addr))
            intEndEvent2->schedule(addr);
        else
            panic("could not find symbol: rti_to_user\n");

        intEndEvent3 = new InterruptEndEvent(&pcEventQueue, "intEndEvent3");
        if (kernelSymtab->findAddress("do_softirq", addr))
            intEndEvent3->schedule(addr + sizeof(MachInst) * 2);
        else
            panic("could not find symbol: do_softirq\n");
    }
}

LinuxSystem::~LinuxSystem()
{
#ifdef DEBUG
    delete kernelPanicEvent;
#endif
    delete skipIdeDelay50msEvent;
    delete skipDelayLoopEvent;
    delete skipCacheProbeEvent;
    delete debugPrintkEvent;
    delete idleStartEvent;
    delete printThreadEvent;
    delete intStartEvent;
    delete intEndEvent;
    delete intEndEvent2;
}

void
LinuxSystem::setDelayLoop(ExecContext *xc)
{
    Addr addr = 0;
    if (kernelSymtab->findAddress("loops_per_jiffy", addr)) {
        Addr paddr = vtophys(physmem, addr);

        uint8_t *loops_per_jiffy =
            physmem->dma_addr(paddr, sizeof(uint32_t));

        Tick cpuFreq = xc->cpu->getFreq();
        Tick intrFreq = platform->interrupt_frequency;
        *(uint32_t *)loops_per_jiffy =
            (uint32_t)((cpuFreq / intrFreq) * 0.9988);
    }
}

BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem)

    SimObjectParam<MemoryController *> mem_ctl;
    SimObjectParam<PhysicalMemory *> physmem;

    Param<string> kernel_code;
    Param<string> console_code;
    Param<string> pal_code;

    Param<string> boot_osflags;
    Param<string> readfile;
    Param<unsigned int> init_param;

    Param<uint64_t> system_type;
    Param<uint64_t> system_rev;

    Param<bool> bin;
    VectorParam<string> binned_fns;
    Param<bool> bin_int;

END_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem)

BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxSystem)

    INIT_PARAM(mem_ctl, "memory controller"),
    INIT_PARAM(physmem, "phsyical memory"),
    INIT_PARAM(kernel_code, "file that contains the kernel code"),
    INIT_PARAM(console_code, "file that contains the console code"),
    INIT_PARAM(pal_code, "file that contains palcode"),
    INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
                    "a"),
    INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
    INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
    INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
    INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
    INIT_PARAM_DFLT(bin, "is this system to be binned", false),
    INIT_PARAM(binned_fns, "functions to be broken down and binned"),
    INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", false)

END_INIT_SIM_OBJECT_PARAMS(LinuxSystem)

CREATE_SIM_OBJECT(LinuxSystem)
{
    System::Params *p = new System::Params;
    p->name = getInstanceName();
    p->memctrl = mem_ctl;
    p->physmem = physmem;
    p->kernel_path = kernel_code;
    p->console_path = console_code;
    p->palcode = pal_code;
    p->boot_osflags = boot_osflags;
    p->init_param = init_param;
    p->readfile = readfile;
    p->system_type = system_type;
    p->system_rev = system_rev;
    p->bin = bin;
    p->binned_fns = binned_fns;
    p->bin_int = bin_int;
    return new LinuxSystem(p);
}

REGISTER_SIM_OBJECT("LinuxSystem", LinuxSystem)

<commit_msg>by default bin interrupts seperately from kernel code.<commit_after>/*
 * Copyright (c) 2004 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders 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
 * This code loads the linux kernel, console, pal and patches certain
 * functions.  The symbol tables are loaded so that traces can show
 * the executing function and we can skip functions. Various delay
 * loops are skipped and their final values manually computed to speed
 * up boot time.
 */

#include "base/trace.hh"
#include "cpu/exec_context.hh"
#include "cpu/base_cpu.hh"
#include "kern/linux/linux_events.hh"
#include "kern/linux/linux_system.hh"
#include "kern/system_events.hh"
#include "mem/functional_mem/memory_control.hh"
#include "mem/functional_mem/physical_memory.hh"
#include "sim/builder.hh"
#include "dev/platform.hh"
#include "targetarch/isa_traits.hh"
#include "targetarch/vtophys.hh"
#include "sim/debug.hh"

extern SymbolTable *debugSymbolTable;

using namespace std;

LinuxSystem::LinuxSystem(Params *p)
    : System(p)
{
    Addr addr = 0;

    /**
     * find the address of the est_cycle_freq variable and insert it
     * so we don't through the lengthly process of trying to
     * calculated it by using the PIT, RTC, etc.
     */
    if (kernelSymtab->findAddress("est_cycle_freq", addr)) {
        Addr paddr = vtophys(physmem, addr);
        uint8_t *est_cycle_frequency =
            physmem->dma_addr(paddr, sizeof(uint64_t));

        if (est_cycle_frequency)
            *(uint64_t *)est_cycle_frequency = htoa(ticksPerSecond);
    }

    /**
     * Since we aren't using a bootloader, we have to copy the kernel arguments
     * directly into the kernels memory.
     */
    {
        Addr paddr = vtophys(physmem, PARAM_ADDR);
        char *commandline = (char*)physmem->dma_addr(paddr, sizeof(uint64_t));
        if (commandline)
            strcpy(commandline, params->boot_osflags.c_str());
    }

    /**
     * EV5 only supports 127 ASNs so we are going to tell the kernel that the
     * paritiuclar EV6 we have only supports 127 asns.
     * @todo At some point we should change ev5.hh and the palcode to support
     * 255 ASNs.
     */
    if (kernelSymtab->findAddress("dp264_mv", addr)) {
        Addr paddr = vtophys(physmem, addr);
        char *dp264_mv = (char *)physmem->dma_addr(paddr, sizeof(uint64_t));

        if (dp264_mv) {
            *(uint32_t*)(dp264_mv+0x18) = htoa((uint32_t)127);
        } else
            panic("could not translate dp264_mv addr\n");

    } else
        panic("could not find dp264_mv\n");

#ifdef DEBUG
    kernelPanicEvent = new BreakPCEvent(&pcEventQueue, "kernel panic");
    if (kernelSymtab->findAddress("panic", addr))
        kernelPanicEvent->schedule(addr);
    else
        panic("could not find kernel symbol \'panic\'");
#endif

    /**
     * Any time ide_delay_50ms, calibarte_delay or
     * determine_cpu_caches is called just skip the
     * function. Currently determine_cpu_caches only is used put
     * information in proc, however if that changes in the future we
     * will have to fill in the cache size variables appropriately.
     */
    skipIdeDelay50msEvent = new SkipFuncEvent(&pcEventQueue, "ide_delay_50ms");
    if (kernelSymtab->findAddress("ide_delay_50ms", addr))
        skipIdeDelay50msEvent->schedule(addr+sizeof(MachInst));

    skipDelayLoopEvent = new LinuxSkipDelayLoopEvent(&pcEventQueue,
                                                     "calibrate_delay");
    if (kernelSymtab->findAddress("calibrate_delay", addr))
        skipDelayLoopEvent->schedule(addr+sizeof(MachInst));

    skipCacheProbeEvent = new SkipFuncEvent(&pcEventQueue,
                                            "determine_cpu_caches");
    if (kernelSymtab->findAddress("determine_cpu_caches", addr))
        skipCacheProbeEvent->schedule(addr+sizeof(MachInst));

    debugPrintkEvent = new DebugPrintkEvent(&pcEventQueue, "dprintk");
    if (kernelSymtab->findAddress("dprintk", addr))
        debugPrintkEvent->schedule(addr+8);

    idleStartEvent = new IdleStartEvent(&pcEventQueue, "cpu_idle", this);
    if (kernelSymtab->findAddress("cpu_idle", addr))
        idleStartEvent->schedule(addr);

    printThreadEvent = new PrintThreadInfo(&pcEventQueue, "threadinfo");
    if (kernelSymtab->findAddress("alpha_switch_to", addr) && DTRACE(Thread))
        printThreadEvent->schedule(addr + sizeof(MachInst) * 6);

    intStartEvent = new InterruptStartEvent(&pcEventQueue, "intStartEvent");

    if (params->bin_int) {
        if (palSymtab->findAddress("sys_int_21", addr))
            intStartEvent->schedule(addr + sizeof(MachInst) * 2);
        else
            panic("could not find symbol: sys_int_21\n");

        intEndEvent = new InterruptEndEvent(&pcEventQueue, "intEndEvent");
        if (palSymtab->findAddress("rti_to_kern", addr))
            intEndEvent->schedule(addr) ;
        else
            panic("could not find symbol: rti_to_kern\n");

        intEndEvent2 = new InterruptEndEvent(&pcEventQueue, "intEndEvent2");
        if (palSymtab->findAddress("rti_to_user", addr))
            intEndEvent2->schedule(addr);
        else
            panic("could not find symbol: rti_to_user\n");

        intEndEvent3 = new InterruptEndEvent(&pcEventQueue, "intEndEvent3");
        if (kernelSymtab->findAddress("do_softirq", addr))
            intEndEvent3->schedule(addr + sizeof(MachInst) * 2);
        else
            panic("could not find symbol: do_softirq\n");
    }
}

LinuxSystem::~LinuxSystem()
{
#ifdef DEBUG
    delete kernelPanicEvent;
#endif
    delete skipIdeDelay50msEvent;
    delete skipDelayLoopEvent;
    delete skipCacheProbeEvent;
    delete debugPrintkEvent;
    delete idleStartEvent;
    delete printThreadEvent;
    delete intStartEvent;
    delete intEndEvent;
    delete intEndEvent2;
}

void
LinuxSystem::setDelayLoop(ExecContext *xc)
{
    Addr addr = 0;
    if (kernelSymtab->findAddress("loops_per_jiffy", addr)) {
        Addr paddr = vtophys(physmem, addr);

        uint8_t *loops_per_jiffy =
            physmem->dma_addr(paddr, sizeof(uint32_t));

        Tick cpuFreq = xc->cpu->getFreq();
        Tick intrFreq = platform->interrupt_frequency;
        *(uint32_t *)loops_per_jiffy =
            (uint32_t)((cpuFreq / intrFreq) * 0.9988);
    }
}

BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem)

    SimObjectParam<MemoryController *> mem_ctl;
    SimObjectParam<PhysicalMemory *> physmem;

    Param<string> kernel_code;
    Param<string> console_code;
    Param<string> pal_code;

    Param<string> boot_osflags;
    Param<string> readfile;
    Param<unsigned int> init_param;

    Param<uint64_t> system_type;
    Param<uint64_t> system_rev;

    Param<bool> bin;
    VectorParam<string> binned_fns;
    Param<bool> bin_int;

END_DECLARE_SIM_OBJECT_PARAMS(LinuxSystem)

BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxSystem)

    INIT_PARAM(mem_ctl, "memory controller"),
    INIT_PARAM(physmem, "phsyical memory"),
    INIT_PARAM(kernel_code, "file that contains the kernel code"),
    INIT_PARAM(console_code, "file that contains the console code"),
    INIT_PARAM(pal_code, "file that contains palcode"),
    INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
                    "a"),
    INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
    INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
    INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
    INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
    INIT_PARAM_DFLT(bin, "is this system to be binned", false),
    INIT_PARAM(binned_fns, "functions to be broken down and binned"),
    INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)

END_INIT_SIM_OBJECT_PARAMS(LinuxSystem)

CREATE_SIM_OBJECT(LinuxSystem)
{
    System::Params *p = new System::Params;
    p->name = getInstanceName();
    p->memctrl = mem_ctl;
    p->physmem = physmem;
    p->kernel_path = kernel_code;
    p->console_path = console_code;
    p->palcode = pal_code;
    p->boot_osflags = boot_osflags;
    p->init_param = init_param;
    p->readfile = readfile;
    p->system_type = system_type;
    p->system_rev = system_rev;
    p->bin = bin;
    p->binned_fns = binned_fns;
    p->bin_int = bin_int;
    return new LinuxSystem(p);
}

REGISTER_SIM_OBJECT("LinuxSystem", LinuxSystem)

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <qgeoboundingcircle.h>
#include <qgeocoordinate.h>

QTM_USE_NAMESPACE

class tst_QGeoBoundingCircle : public QObject
{
    Q_OBJECT
};

QTEST_MAIN(tst_QGeoBoundingCircle)
#include "tst_qgeoboundingcircle.moc"
<commit_msg>Fleshing out auto tests for QGeoBoundingCircle<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <qgeoboundingcircle.h>
#include <qgeocoordinate.h>

QTM_USE_NAMESPACE

Q_DECLARE_METATYPE(QGeoCoordinate)

class tst_QGeoBoundingCircle : public QObject
{
    Q_OBJECT

private slots:
    void defaultConstructor();
    void centerRadiusConstructor();

    void comparison();
    void type();

    void radius();
    void center();

    void translate_data();
    void translate();

    void valid_data();
    void valid();

    void empty_data();
    void empty();

    void contains_data();
    void contains();
};

void tst_QGeoBoundingCircle::defaultConstructor()
{
    QGeoBoundingCircle c;
    QVERIFY(!c.center().isValid());
    QCOMPARE(c.radius(), -1.0);
}

void tst_QGeoBoundingCircle::centerRadiusConstructor()
{
    QGeoBoundingCircle c(QGeoCoordinate(1,1), 50);
    QCOMPARE(c.center(), QGeoCoordinate(1,1));
    QCOMPARE(c.radius(), 50.0);
}

void tst_QGeoBoundingCircle::comparison()
{
    QGeoBoundingCircle c1(QGeoCoordinate(1,1), 50);
    QGeoBoundingCircle c2(QGeoCoordinate(1,1), 50);
    QGeoBoundingCircle c3(QGeoCoordinate(1,1), 35);
    QGeoBoundingCircle c4(QGeoCoordinate(1,2), 50);

    QVERIFY(c1 == c2);
    QVERIFY(c1 != c3);
    QVERIFY(c1 != c4);
    QVERIFY(c2 != c3);
}

void tst_QGeoBoundingCircle::type()
{
    QGeoBoundingCircle c;
    QCOMPARE(c.type(), QGeoBoundingArea::CircleType);
}

void tst_QGeoBoundingCircle::radius()
{
    QGeoBoundingCircle c;
    c.setRadius(1.0);
    QCOMPARE(c.radius(), 1.0);
    c.setRadius(5.0);
    QCOMPARE(c.radius(), 5.0);
}

void tst_QGeoBoundingCircle::center()
{
    QGeoBoundingCircle c;
    c.setCenter(QGeoCoordinate(1,1));
    QCOMPARE(c.center(), QGeoCoordinate(1,1));
    c.setCenter(QGeoCoordinate(5,10));
    QCOMPARE(c.center(), QGeoCoordinate(5,10));
}

void tst_QGeoBoundingCircle::translate_data()
{
    QTest::addColumn<QGeoCoordinate>("center");
    QTest::addColumn<qreal>("radius");
    QTest::addColumn<qreal>("lat");
    QTest::addColumn<qreal>("lon");
    QTest::addColumn<QGeoCoordinate>("newCenter");

    QTest::newRow("from 0,0") << QGeoCoordinate(0,0) << 10.0 <<
                                 5.0 << 5.0 << QGeoCoordinate(5.0, 5.0);
    QTest::newRow("across 0,0") << QGeoCoordinate(-2, -2) << 20.0 <<
                                   5.0 << 5.0 << QGeoCoordinate(3.0, 3.0);
    QTest::newRow("backwards accross 0,0") << QGeoCoordinate(5,5) << 50.0
                                              << -13.0 << 5.0
                                              << QGeoCoordinate(-8.0, 10.0);
}

void tst_QGeoBoundingCircle::translate()
{
    QFETCH(QGeoCoordinate, center);
    QFETCH(qreal, radius);
    QFETCH(qreal, lat);
    QFETCH(qreal, lon);
    QFETCH(QGeoCoordinate, newCenter);

    QGeoBoundingCircle c(center, radius);
    QGeoBoundingCircle d = c;

    c.translate(lat, lon);

    QCOMPARE(c.radius(), radius);
    QCOMPARE(c.center(), newCenter);

    c = d.translated(lat, lon);
    d.setRadius(1.0);

    QCOMPARE(c.radius(), radius);
    QCOMPARE(d.center(), center);
    QCOMPARE(c.center(), newCenter);
}

void tst_QGeoBoundingCircle::valid_data()
{
    QTest::addColumn<QGeoCoordinate>("center");
    QTest::addColumn<qreal>("radius");
    QTest::addColumn<bool>("valid");

    QTest::newRow("default") << QGeoCoordinate() << -1.0 << false;
    QTest::newRow("empty coord") << QGeoCoordinate() << 5.0 << false;
    QTest::newRow("NaN coord") << QGeoCoordinate(500, 500) << 5.0 << false;
    QTest::newRow("bad radius") << QGeoCoordinate(10, 10) << -5.0 << false;
    QTest::newRow("NaN radius") << QGeoCoordinate(10, 10) << qQNaN() << false;
    QTest::newRow("zero radius") << QGeoCoordinate(10, 10) << 0.0 << true;
    QTest::newRow("good") << QGeoCoordinate(10, 10) << 5.0 << true;
}

void tst_QGeoBoundingCircle::valid()
{
    QFETCH(QGeoCoordinate, center);
    QFETCH(qreal, radius);
    QFETCH(bool, valid);

    QGeoBoundingCircle c(center, radius);
    QCOMPARE(c.isValid(), valid);
}

void tst_QGeoBoundingCircle::empty_data()
{
    QTest::addColumn<QGeoCoordinate>("center");
    QTest::addColumn<qreal>("radius");
    QTest::addColumn<bool>("empty");

    QTest::newRow("default") << QGeoCoordinate() << -1.0 << true;
    QTest::newRow("empty coord") << QGeoCoordinate() << 5.0 << true;
    QTest::newRow("NaN coord") << QGeoCoordinate(500, 500) << 5.0 << true;
    QTest::newRow("bad radius") << QGeoCoordinate(10, 10) << -5.0 << true;
    QTest::newRow("NaN radius") << QGeoCoordinate(10, 10) << qQNaN() << true;
    QTest::newRow("zero radius") << QGeoCoordinate(10, 10) << 0.0 << true;
    QTest::newRow("good") << QGeoCoordinate(10, 10) << 5.0 << false;
}

void tst_QGeoBoundingCircle::empty()
{
    QFETCH(QGeoCoordinate, center);
    QFETCH(qreal, radius);
    QFETCH(bool, empty);

    QGeoBoundingCircle c(center, radius);
    QCOMPARE(c.isEmpty(), empty);
}

void tst_QGeoBoundingCircle::contains_data()
{
    QTest::addColumn<QGeoCoordinate>("center");
    QTest::addColumn<qreal>("radius");
    QTest::addColumn<QGeoCoordinate>("probe");
    QTest::addColumn<bool>("result");

    QTest::newRow("own centre") << QGeoCoordinate(1,1) << 100.0 <<
                                   QGeoCoordinate(1,1) << true;
    QTest::newRow("over the hills") << QGeoCoordinate(1,1) << 100.0 <<
                                       QGeoCoordinate(30, 40) << false;
    QTest::newRow("at 0.5*radius") << QGeoCoordinate(1,1) << 100.0 <<
                                      QGeoCoordinate(1.00015374,1.00015274) << true;
    QTest::newRow("at 0.99*radius") << QGeoCoordinate(1,1) << 100.0 <<
                                       QGeoCoordinate(1.00077538, 0.99955527) << true;
    QTest::newRow("at 1.01*radius") << QGeoCoordinate(1,1) << 100.0 <<
                                       QGeoCoordinate(1.00071413, 0.99943423) << false;
}

void tst_QGeoBoundingCircle::contains()
{
    QFETCH(QGeoCoordinate, center);
    QFETCH(qreal, radius);
    QFETCH(QGeoCoordinate, probe);
    QFETCH(bool, result);

    QGeoBoundingCircle c(center, radius);
    QCOMPARE(c.contains(probe), result);
}

QTEST_MAIN(tst_QGeoBoundingCircle)
#include "tst_qgeoboundingcircle.moc"
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QByteArray>

#include <QtScript>

#if defined(Q_OS_SYMBIAN)
# define SRCDIR ""
#endif

//TESTED_CLASS=
//TESTED_FILES=

// Uncomment the following define to have the autotest generate
// addExpectedFailure() code for all the tests that fail.
// This is useful when a whole new test (sub)suite is added.
// The code is stored in addexpectedfailures.cpp.
// Paste the contents into this file after the existing
// addExpectedFailure() calls.

//#define GENERATE_ADDEXPECTEDFAILURE_CODE

static QString readFile(const QString &filename)
{
    QFile file(filename);
    if (!file.open(QFile::ReadOnly))
        return QString();
    QTextStream stream(&file);
    stream.setCodec("UTF-8");
    return stream.readAll();
}

static void appendCString(QVector<char> *v, const char *s)
{
    char c;
    do {
        c = *(s++);
        *v << c;
    } while (c != '\0');
}

struct ExpectedFailure
{
    ExpectedFailure(const QString &name, const QString &act,
                    const QString &exp, const QString &msg)
        : testName(name), actual(act), expected(exp), message(msg)
        { }

    QString testName;
    QString actual;
    QString expected;
    QString message;
};

class tst_Suite : public QObject
{

public:
    tst_Suite();
    virtual ~tst_Suite();

    static QMetaObject staticMetaObject;
    virtual const QMetaObject *metaObject() const;
    virtual void *qt_metacast(const char *);
    virtual int qt_metacall(QMetaObject::Call, int, void **argv);

private:
    void addExpectedFailure(const QString &testName, const QString &actual,
                            const QString &expected, const QString &message);
    bool isExpectedFailure(const QString &testName, const QString &actual,
                           const QString &expected, QString *message) const;
    void addTestExclusion(const QString &testName, const QString &message);
    void addTestExclusion(const QRegExp &rx, const QString &message);
    bool isExcludedTest(const QString &testName, QString *message) const;

    QDir testsDir;
    QStringList testNames;
    QList<ExpectedFailure> expectedFailures;
    QList<QPair<QRegExp, QString> > testExclusions;
    QString mjsunitContents;
#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE
    QString generatedAddExpectedFailureCode;
#endif
};

QMetaObject tst_Suite::staticMetaObject;

Q_GLOBAL_STATIC(QVector<uint>, qt_meta_data_tst_Suite)
Q_GLOBAL_STATIC(QVector<char>, qt_meta_stringdata_tst_Suite)

const QMetaObject *tst_Suite::metaObject() const
{
    return &staticMetaObject;
}

void *tst_Suite::qt_metacast(const char *_clname)
{
    if (!_clname) return 0;
    if (!strcmp(_clname, qt_meta_stringdata_tst_Suite()->constData()))
        return static_cast<void*>(const_cast<tst_Suite*>(this));
    return QObject::qt_metacast(_clname);
}

static QScriptValue qscript_fail(QScriptContext *ctx, QScriptEngine *eng)
{
    QScriptValue realFail = ctx->callee().data();
    Q_ASSERT(realFail.isFunction());
    QScriptValue ret = realFail.call(ctx->thisObject(), ctx->argumentsObject());
    Q_ASSERT(eng->hasUncaughtException());
    ret.setProperty("expected", ctx->argument(0));
    ret.setProperty("actual", ctx->argument(1));
    QScriptContextInfo info(ctx->parentContext()->parentContext());
    ret.setProperty("lineNumber", info.lineNumber());
    return ret;
}

int tst_Suite::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
    _id = QObject::qt_metacall(_c, _id, _a);
    if (_id < 0)
        return _id;
    if (_c == QMetaObject::InvokeMetaMethod) {
        QString name = testNames.at(_id);
        QString path = testsDir.absoluteFilePath(name + ".js");
        QString excludeMessage;
        if (isExcludedTest(name, &excludeMessage)) {
            QTest::qSkip(excludeMessage.toLatin1(), QTest::SkipAll, path.toLatin1(), -1);
        } else {
            QScriptEngine engine;
            engine.evaluate(mjsunitContents).toString();
            if (engine.hasUncaughtException()) {
                QStringList bt = engine.uncaughtExceptionBacktrace();
                QString err = engine.uncaughtException().toString();
                qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n")));
            } else {
                QScriptValue fakeFail = engine.newFunction(qscript_fail);
                fakeFail.setData(engine.globalObject().property("fail"));
                engine.globalObject().setProperty("fail", fakeFail);
                QString contents = readFile(path);
                QScriptValue ret = engine.evaluate(contents);
                if (engine.hasUncaughtException()) {
                    if (!ret.isError()) {
                        Q_ASSERT(ret.instanceOf(engine.globalObject().property("MjsUnitAssertionError")));
                        QString actual = ret.property("actual").toString();
                        QString expected = ret.property("expected").toString();
                        int lineNumber = ret.property("lineNumber").toInt32();
                        QString failMessage;
                        if (isExpectedFailure(name, actual, expected, &failMessage)) {
                            QTest::qExpectFail("", failMessage.toLatin1(),
                                               QTest::Continue, path.toLatin1(),
                                               lineNumber);
                        }
#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE
                        else {
                            generatedAddExpectedFailureCode.append(
                                "    addExpectedFailure(\"" + name
                                + "\", \"" + actual + "\", \"" + expected
                                + "\", willFixInNextReleaseMessage);\n");
                        }
#endif
                        QTest::qCompare(actual, expected, "actual", "expect",
                                        path.toLatin1(), lineNumber);
                    } else {
                        int lineNumber = ret.property("lineNumber").toInt32();
                        QTest::qExpectFail("", ret.toString().toLatin1(),
                                           QTest::Continue, path.toLatin1(), lineNumber);
                        QTest::qVerify(false, ret.toString().toLatin1(), "", path.toLatin1(), lineNumber);
                    }
                }
            }
        }
        _id -= testNames.size();
    }
    return _id;
}

tst_Suite::tst_Suite()
{
    testsDir = QDir(SRCDIR);
    bool testsFound = testsDir.cd("tests");
    if (!testsFound) {
        qWarning("*** no tests/ dir!");
    } else {
        if (!testsDir.exists("mjsunit.js"))
            qWarning("*** no tests/mjsunit.js file!");
        else {
            mjsunitContents = readFile(testsDir.absoluteFilePath("mjsunit.js"));
            if (mjsunitContents.isEmpty())
                qWarning("*** tests/mjsunit.js is empty!");
        }
    }
    QString willFixInNextReleaseMessage = QString::fromLatin1("Will fix in next release");
    addExpectedFailure("arguments-enum", "2", "0", willFixInNextReleaseMessage);
    addExpectedFailure("const-redecl", "undefined", "TypeError", willFixInNextReleaseMessage);
    addExpectedFailure("global-const-var-conflicts", "false", "true", willFixInNextReleaseMessage);
    addExpectedFailure("string-lastindexof", "0", "-1", "test is wrong?");

    addTestExclusion("debug-*", "not applicable");
    addTestExclusion("mirror-*", "not applicable");

    addTestExclusion("array-concat", "Hangs on JSC backend");
    addTestExclusion("array-splice", "Hangs on JSC backend");
    addTestExclusion("sparse-array-reverse", "Hangs on JSC backend");

    addTestExclusion("string-case", "V8-specific behavior? (Doesn't pass on SpiderMonkey either)");

#ifdef Q_OS_WINCE
    addTestExclusion("deep-recursion", "Demands too much memory on WinCE");
    addTestExclusion("nested-repetition-count-overflow", "Demands too much memory on WinCE");
    addTestExclusion("unicode-test", "Demands too much memory on WinCE");
    addTestExclusion("mul-exhaustive", "Demands too much memory on WinCE");
#endif

#ifdef Q_OS_SYMBIAN
    addTestExclusion("nested-repetition-count-overflow", "Demands too much memory on Symbian");
    addTestExclusion("unicode-test", "Demands too much memory on Symbian");
#endif
    // Failures due to switch to JSC as back-end
    addExpectedFailure("date-parse", "NaN", "946713600000", willFixInNextReleaseMessage);
    addExpectedFailure("delete-global-properties", "true", "false", willFixInNextReleaseMessage);
    addExpectedFailure("delete", "false", "true", willFixInNextReleaseMessage);
    addExpectedFailure("function-arguments-null", "false", "true", willFixInNextReleaseMessage);
    addExpectedFailure("function-caller", "null", "function eval() {\n    [native code]\n}", willFixInNextReleaseMessage);
    addExpectedFailure("function-prototype", "prototype", "disconnectconnect", willFixInNextReleaseMessage);
    addExpectedFailure("number-tostring", "0", "0.0000a7c5ac471b4788", willFixInNextReleaseMessage);
    addExpectedFailure("parse-int-float", "1e+21", "1", willFixInNextReleaseMessage);
    addExpectedFailure("regexp", "false", "true", willFixInNextReleaseMessage);
    addExpectedFailure("smi-negative-zero", "-Infinity", "Infinity", willFixInNextReleaseMessage);
    addExpectedFailure("string-split", "4", "3", willFixInNextReleaseMessage);
    addExpectedFailure("substr", "abcdefghijklmn", "", willFixInNextReleaseMessage);

    static const char klass[] = "tst_QScriptV8TestSuite";

    QVector<uint> *data = qt_meta_data_tst_Suite();
    // content:
    *data << 1 // revision
          << 0 // classname
          << 0 << 0 // classinfo
          << 0 << 10 // methods (backpatched later)
          << 0 << 0 // properties
          << 0 << 0 // enums/sets
        ;

    QVector<char> *stringdata = qt_meta_stringdata_tst_Suite();
    appendCString(stringdata, klass);
    appendCString(stringdata, "");

    QFileInfoList testFileInfos;
    if (testsFound)
        testFileInfos = testsDir.entryInfoList(QStringList() << "*.js", QDir::Files);
    foreach (QFileInfo tfi, testFileInfos) {
        QString name = tfi.baseName();
        // slot: signature, parameters, type, tag, flags
        QString slot = QString::fromLatin1("%0()").arg(name);
        static const int nullbyte = sizeof(klass);
        *data << stringdata->size() << nullbyte << nullbyte << nullbyte << 0x08;
        appendCString(stringdata, slot.toLatin1());
        testNames.append(name);
    }

    (*data)[4] = testFileInfos.size();

    *data << 0; // eod

    // initialize staticMetaObject
    staticMetaObject.d.superdata = &QObject::staticMetaObject;
    staticMetaObject.d.stringdata = stringdata->constData();
    staticMetaObject.d.data = data->constData();
    staticMetaObject.d.extradata = 0;
}

tst_Suite::~tst_Suite()
{
#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE
    if (!generatedAddExpectedFailureCode.isEmpty()) {
        QFile file("addexpectedfailures.cpp");
        file.open(QFile::WriteOnly);
        QTextStream ts(&file);
        ts << generatedAddExpectedFailureCode;
    }
#endif
}

void tst_Suite::addExpectedFailure(const QString &testName, const QString &actual,
                                   const QString &expected, const QString &message)
{
    expectedFailures.append(ExpectedFailure(testName, actual, expected, message));
}

bool tst_Suite::isExpectedFailure(const QString &testName, const QString &actual,
                                  const QString &expected, QString *message) const
{
    for (int i = 0; i < expectedFailures.size(); ++i) {
        const ExpectedFailure &ef = expectedFailures.at(i);
        if ((testName == ef.testName) && (actual == ef.actual) && (expected == ef.expected)) {
            if (message)
                *message = ef.message;
            return true;
        }
    }
    return false;
}

void tst_Suite::addTestExclusion(const QString &testName, const QString &message)
{
    testExclusions.append(qMakePair(QRegExp(testName), message));
}

void tst_Suite::addTestExclusion(const QRegExp &rx, const QString &message)
{
    testExclusions.append(qMakePair(rx, message));
}

bool tst_Suite::isExcludedTest(const QString &testName, QString *message) const
{
    for (int i = 0; i < testExclusions.size(); ++i) {
        if (testExclusions.at(i).first.indexIn(testName) != -1) {
            if (message)
                *message = testExclusions.at(i).second;
            return true;
        }
    }
    return false;
}

QTEST_MAIN(tst_Suite)
<commit_msg>Skip test that crashes on win32-g++<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QByteArray>

#include <QtScript>

#if defined(Q_OS_SYMBIAN)
# define SRCDIR ""
#endif

//TESTED_CLASS=
//TESTED_FILES=

// Uncomment the following define to have the autotest generate
// addExpectedFailure() code for all the tests that fail.
// This is useful when a whole new test (sub)suite is added.
// The code is stored in addexpectedfailures.cpp.
// Paste the contents into this file after the existing
// addExpectedFailure() calls.

//#define GENERATE_ADDEXPECTEDFAILURE_CODE

static QString readFile(const QString &filename)
{
    QFile file(filename);
    if (!file.open(QFile::ReadOnly))
        return QString();
    QTextStream stream(&file);
    stream.setCodec("UTF-8");
    return stream.readAll();
}

static void appendCString(QVector<char> *v, const char *s)
{
    char c;
    do {
        c = *(s++);
        *v << c;
    } while (c != '\0');
}

struct ExpectedFailure
{
    ExpectedFailure(const QString &name, const QString &act,
                    const QString &exp, const QString &msg)
        : testName(name), actual(act), expected(exp), message(msg)
        { }

    QString testName;
    QString actual;
    QString expected;
    QString message;
};

class tst_Suite : public QObject
{

public:
    tst_Suite();
    virtual ~tst_Suite();

    static QMetaObject staticMetaObject;
    virtual const QMetaObject *metaObject() const;
    virtual void *qt_metacast(const char *);
    virtual int qt_metacall(QMetaObject::Call, int, void **argv);

private:
    void addExpectedFailure(const QString &testName, const QString &actual,
                            const QString &expected, const QString &message);
    bool isExpectedFailure(const QString &testName, const QString &actual,
                           const QString &expected, QString *message) const;
    void addTestExclusion(const QString &testName, const QString &message);
    void addTestExclusion(const QRegExp &rx, const QString &message);
    bool isExcludedTest(const QString &testName, QString *message) const;

    QDir testsDir;
    QStringList testNames;
    QList<ExpectedFailure> expectedFailures;
    QList<QPair<QRegExp, QString> > testExclusions;
    QString mjsunitContents;
#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE
    QString generatedAddExpectedFailureCode;
#endif
};

QMetaObject tst_Suite::staticMetaObject;

Q_GLOBAL_STATIC(QVector<uint>, qt_meta_data_tst_Suite)
Q_GLOBAL_STATIC(QVector<char>, qt_meta_stringdata_tst_Suite)

const QMetaObject *tst_Suite::metaObject() const
{
    return &staticMetaObject;
}

void *tst_Suite::qt_metacast(const char *_clname)
{
    if (!_clname) return 0;
    if (!strcmp(_clname, qt_meta_stringdata_tst_Suite()->constData()))
        return static_cast<void*>(const_cast<tst_Suite*>(this));
    return QObject::qt_metacast(_clname);
}

static QScriptValue qscript_fail(QScriptContext *ctx, QScriptEngine *eng)
{
    QScriptValue realFail = ctx->callee().data();
    Q_ASSERT(realFail.isFunction());
    QScriptValue ret = realFail.call(ctx->thisObject(), ctx->argumentsObject());
    Q_ASSERT(eng->hasUncaughtException());
    ret.setProperty("expected", ctx->argument(0));
    ret.setProperty("actual", ctx->argument(1));
    QScriptContextInfo info(ctx->parentContext()->parentContext());
    ret.setProperty("lineNumber", info.lineNumber());
    return ret;
}

int tst_Suite::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
    _id = QObject::qt_metacall(_c, _id, _a);
    if (_id < 0)
        return _id;
    if (_c == QMetaObject::InvokeMetaMethod) {
        QString name = testNames.at(_id);
        QString path = testsDir.absoluteFilePath(name + ".js");
        QString excludeMessage;
        if (isExcludedTest(name, &excludeMessage)) {
            QTest::qSkip(excludeMessage.toLatin1(), QTest::SkipAll, path.toLatin1(), -1);
        } else {
            QScriptEngine engine;
            engine.evaluate(mjsunitContents).toString();
            if (engine.hasUncaughtException()) {
                QStringList bt = engine.uncaughtExceptionBacktrace();
                QString err = engine.uncaughtException().toString();
                qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n")));
            } else {
                QScriptValue fakeFail = engine.newFunction(qscript_fail);
                fakeFail.setData(engine.globalObject().property("fail"));
                engine.globalObject().setProperty("fail", fakeFail);
                QString contents = readFile(path);
                QScriptValue ret = engine.evaluate(contents);
                if (engine.hasUncaughtException()) {
                    if (!ret.isError()) {
                        Q_ASSERT(ret.instanceOf(engine.globalObject().property("MjsUnitAssertionError")));
                        QString actual = ret.property("actual").toString();
                        QString expected = ret.property("expected").toString();
                        int lineNumber = ret.property("lineNumber").toInt32();
                        QString failMessage;
                        if (isExpectedFailure(name, actual, expected, &failMessage)) {
                            QTest::qExpectFail("", failMessage.toLatin1(),
                                               QTest::Continue, path.toLatin1(),
                                               lineNumber);
                        }
#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE
                        else {
                            generatedAddExpectedFailureCode.append(
                                "    addExpectedFailure(\"" + name
                                + "\", \"" + actual + "\", \"" + expected
                                + "\", willFixInNextReleaseMessage);\n");
                        }
#endif
                        QTest::qCompare(actual, expected, "actual", "expect",
                                        path.toLatin1(), lineNumber);
                    } else {
                        int lineNumber = ret.property("lineNumber").toInt32();
                        QTest::qExpectFail("", ret.toString().toLatin1(),
                                           QTest::Continue, path.toLatin1(), lineNumber);
                        QTest::qVerify(false, ret.toString().toLatin1(), "", path.toLatin1(), lineNumber);
                    }
                }
            }
        }
        _id -= testNames.size();
    }
    return _id;
}

tst_Suite::tst_Suite()
{
    testsDir = QDir(SRCDIR);
    bool testsFound = testsDir.cd("tests");
    if (!testsFound) {
        qWarning("*** no tests/ dir!");
    } else {
        if (!testsDir.exists("mjsunit.js"))
            qWarning("*** no tests/mjsunit.js file!");
        else {
            mjsunitContents = readFile(testsDir.absoluteFilePath("mjsunit.js"));
            if (mjsunitContents.isEmpty())
                qWarning("*** tests/mjsunit.js is empty!");
        }
    }
    QString willFixInNextReleaseMessage = QString::fromLatin1("Will fix in next release");
    addExpectedFailure("arguments-enum", "2", "0", willFixInNextReleaseMessage);
    addExpectedFailure("const-redecl", "undefined", "TypeError", willFixInNextReleaseMessage);
    addExpectedFailure("global-const-var-conflicts", "false", "true", willFixInNextReleaseMessage);
    addExpectedFailure("string-lastindexof", "0", "-1", "test is wrong?");

    addTestExclusion("debug-*", "not applicable");
    addTestExclusion("mirror-*", "not applicable");

    addTestExclusion("array-concat", "Hangs on JSC backend");
    addTestExclusion("array-splice", "Hangs on JSC backend");
    addTestExclusion("sparse-array-reverse", "Hangs on JSC backend");

    addTestExclusion("string-case", "V8-specific behavior? (Doesn't pass on SpiderMonkey either)");

#ifdef Q_CC_MINGW
    addTestExclusion("date$", "QTBUG-7698: Date.prototype.setMonth() crashes on win32-g++");
#endif

#ifdef Q_OS_WINCE
    addTestExclusion("deep-recursion", "Demands too much memory on WinCE");
    addTestExclusion("nested-repetition-count-overflow", "Demands too much memory on WinCE");
    addTestExclusion("unicode-test", "Demands too much memory on WinCE");
    addTestExclusion("mul-exhaustive", "Demands too much memory on WinCE");
#endif

#ifdef Q_OS_SYMBIAN
    addTestExclusion("nested-repetition-count-overflow", "Demands too much memory on Symbian");
    addTestExclusion("unicode-test", "Demands too much memory on Symbian");
#endif
    // Failures due to switch to JSC as back-end
    addExpectedFailure("date-parse", "NaN", "946713600000", willFixInNextReleaseMessage);
    addExpectedFailure("delete-global-properties", "true", "false", willFixInNextReleaseMessage);
    addExpectedFailure("delete", "false", "true", willFixInNextReleaseMessage);
    addExpectedFailure("function-arguments-null", "false", "true", willFixInNextReleaseMessage);
    addExpectedFailure("function-caller", "null", "function eval() {\n    [native code]\n}", willFixInNextReleaseMessage);
    addExpectedFailure("function-prototype", "prototype", "disconnectconnect", willFixInNextReleaseMessage);
    addExpectedFailure("number-tostring", "0", "0.0000a7c5ac471b4788", willFixInNextReleaseMessage);
    addExpectedFailure("parse-int-float", "1e+21", "1", willFixInNextReleaseMessage);
    addExpectedFailure("regexp", "false", "true", willFixInNextReleaseMessage);
    addExpectedFailure("smi-negative-zero", "-Infinity", "Infinity", willFixInNextReleaseMessage);
    addExpectedFailure("string-split", "4", "3", willFixInNextReleaseMessage);
    addExpectedFailure("substr", "abcdefghijklmn", "", willFixInNextReleaseMessage);

    static const char klass[] = "tst_QScriptV8TestSuite";

    QVector<uint> *data = qt_meta_data_tst_Suite();
    // content:
    *data << 1 // revision
          << 0 // classname
          << 0 << 0 // classinfo
          << 0 << 10 // methods (backpatched later)
          << 0 << 0 // properties
          << 0 << 0 // enums/sets
        ;

    QVector<char> *stringdata = qt_meta_stringdata_tst_Suite();
    appendCString(stringdata, klass);
    appendCString(stringdata, "");

    QFileInfoList testFileInfos;
    if (testsFound)
        testFileInfos = testsDir.entryInfoList(QStringList() << "*.js", QDir::Files);
    foreach (QFileInfo tfi, testFileInfos) {
        QString name = tfi.baseName();
        // slot: signature, parameters, type, tag, flags
        QString slot = QString::fromLatin1("%0()").arg(name);
        static const int nullbyte = sizeof(klass);
        *data << stringdata->size() << nullbyte << nullbyte << nullbyte << 0x08;
        appendCString(stringdata, slot.toLatin1());
        testNames.append(name);
    }

    (*data)[4] = testFileInfos.size();

    *data << 0; // eod

    // initialize staticMetaObject
    staticMetaObject.d.superdata = &QObject::staticMetaObject;
    staticMetaObject.d.stringdata = stringdata->constData();
    staticMetaObject.d.data = data->constData();
    staticMetaObject.d.extradata = 0;
}

tst_Suite::~tst_Suite()
{
#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE
    if (!generatedAddExpectedFailureCode.isEmpty()) {
        QFile file("addexpectedfailures.cpp");
        file.open(QFile::WriteOnly);
        QTextStream ts(&file);
        ts << generatedAddExpectedFailureCode;
    }
#endif
}

void tst_Suite::addExpectedFailure(const QString &testName, const QString &actual,
                                   const QString &expected, const QString &message)
{
    expectedFailures.append(ExpectedFailure(testName, actual, expected, message));
}

bool tst_Suite::isExpectedFailure(const QString &testName, const QString &actual,
                                  const QString &expected, QString *message) const
{
    for (int i = 0; i < expectedFailures.size(); ++i) {
        const ExpectedFailure &ef = expectedFailures.at(i);
        if ((testName == ef.testName) && (actual == ef.actual) && (expected == ef.expected)) {
            if (message)
                *message = ef.message;
            return true;
        }
    }
    return false;
}

void tst_Suite::addTestExclusion(const QString &testName, const QString &message)
{
    testExclusions.append(qMakePair(QRegExp(testName), message));
}

void tst_Suite::addTestExclusion(const QRegExp &rx, const QString &message)
{
    testExclusions.append(qMakePair(rx, message));
}

bool tst_Suite::isExcludedTest(const QString &testName, QString *message) const
{
    for (int i = 0; i < testExclusions.size(); ++i) {
        if (testExclusions.at(i).first.indexIn(testName) != -1) {
            if (message)
                *message = testExclusions.at(i).second;
            return true;
        }
    }
    return false;
}

QTEST_MAIN(tst_Suite)
<|endoftext|>


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

#include <nvtt/nvtt.h>
#include <nvimage/Image.h>
#include <nvimage/ImageIO.h>
#include <nvimage/BlockDXT.h>
#include <nvimage/ColorBlock.h>
#include <nvmath/KahanSum.h>
#include <nvcore/Ptr.h>
#include <nvcore/Debug.h>
#include <nvcore/StrLib.h>
#include <nvcore/StdStream.h>
#include <nvcore/TextWriter.h>
#include <nvcore/FileSystem.h>

#include <stdlib.h> // free
#include <string.h> // memcpy
#include <time.h> // clock

using namespace nv;

static const char * s_fileNames[] = {
	// Kodak image set
	"kodim01.png",
	"kodim02.png",
	"kodim03.png",
	"kodim04.png",
	"kodim05.png",
	"kodim06.png",
	"kodim07.png",
	"kodim08.png",
	"kodim09.png",
	"kodim10.png",
	"kodim11.png",
	"kodim12.png",
	"kodim13.png",
	"kodim14.png",
	"kodim15.png",
	"kodim16.png",
	"kodim17.png",
	"kodim18.png",
	"kodim19.png",
	"kodim20.png",
	"kodim21.png",
	"kodim22.png",
	"kodim23.png",
	"kodim24.png",
	// Waterloo image set
	"clegg.png",
	"frymire.png",
	"lena.png",
	"monarch.png",
	"peppers.png",
	"sail.png",
	"serrano.png",
	"tulips.png",
	// Epic image set
	"Bradley1.png",
	"Gradient.png",
	"MoreRocks.png",
	"Wall.png",
	"Rainbow.png",
	"Text.png",
};
const int s_fileCount = sizeof(s_fileNames)/sizeof(s_fileNames[0]);

struct MyOutputHandler : public nvtt::OutputHandler
{
	MyOutputHandler() : m_data(NULL), m_ptr(NULL) {}
	~MyOutputHandler()
	{
		free(m_data);
	}

	virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
	{
		m_size = size;
		m_width = width;
		m_height = height;
		free(m_data);
		m_data = (unsigned char *)malloc(size);
		m_ptr = m_data;
	}

	virtual bool writeData(const void * data, int size)
	{
		memcpy(m_ptr, data, size);
		m_ptr += size;
		return true;
	}

	Image * decompress(nvtt::Format format)
	{
		int bw = (m_width + 3) / 4;
		int bh = (m_height + 3) / 4;

		AutoPtr<Image> img( new Image() );
		img->allocate(m_width, m_height);

		if (format == nvtt::Format_BC1)
		{
			BlockDXT1 * block = (BlockDXT1 *)m_data;

			for (int y = 0; y < bh; y++)
			{
				for (int x = 0; x < bw; x++)
				{
					ColorBlock colors;
					block->decodeBlock(&colors);

					for (int yy = 0; yy < 4; yy++)
					{
						for (int xx = 0; xx < 4; xx++)
						{
							Color32 c = colors.color(xx, yy);

							if (x * 4 + xx < m_width && y * 4 + yy < m_height)
							{
								img->pixel(x * 4 + xx, y * 4 + yy) = c;
							}
						}
					}

					block++;
				}
			}
		}

		return img.release();
	}

	int m_size;
	int m_width;
	int m_height;
	unsigned char * m_data;
	unsigned char * m_ptr;
};

float rmsError(const Image * a, const Image * b)
{
	nvCheck(a != NULL);
	nvCheck(b != NULL);
	nvCheck(a->width() == b->width());
	nvCheck(a->height() == b->height());

	KahanSum mse;

	const uint count = a->width() * a->height();

	for (uint i = 0; i < count; i++)
	{
		Color32 c0 = a->pixel(i);
		Color32 c1 = b->pixel(i);

		int r = c0.r - c1.r;
		int g = c0.g - c1.g;
		int b = c0.b - c1.b;
		//int a = c0.a - c1.a;

		mse.add(r * r);
		mse.add(g * g);
		mse.add(b * b);
	}

	return sqrtf(mse.sum() / count);
}

int main(int argc, char *argv[])
{
	const uint version = nvtt::version();
	const uint major = version / 100;
	const uint minor = version % 100;

	printf("NVIDIA Texture Tools %u.%u - Copyright NVIDIA Corporation 2007 - 2008\n\n", major, minor);

	bool fast = false;
	bool nocuda = false;
	bool showHelp = false;
	const char * outPath = "output";
	const char * regressPath = NULL;

	// Parse arguments.
	for (int i = 1; i < argc; i++)
	{
		if (strcmp("-fast", argv[i]) == 0)
		{
			fast = true;
		}
		else if (strcmp("-nocuda", argv[i]) == 0)
		{
			nocuda = true;
		}
		else if (strcmp("-help", argv[i]) == 0)
		{
			showHelp = true;
		}
		else if (strcmp("-out", argv[i]) == 0)
		{
			if (i+1 < argc && argv[i+1][0] != '-') outPath = argv[i+1];
		}
		else if (strcmp("-regress", argv[i]) == 0)
		{
			if (i+1 < argc && argv[i+1][0] != '-') regressPath = argv[i+1];
		}
	}

	if (showHelp)
	{
		printf("usage: nvtestsuite [options]\n\n");

		printf("Input options:\n");
		printf("  -regress <path>\tRegression directory.\n");

		printf("Compression options:\n");
		printf("  -fast          \tFast compression.\n");
		printf("  -nocuda        \tDo not use cuda compressor.\n");

		printf("Output options:\n");
		printf("  -out <path>    \tOutput directory.\n");

		return 1;
	}

	nvtt::InputOptions inputOptions;
	inputOptions.setMipmapGeneration(false);

	nvtt::CompressionOptions compressionOptions;
	compressionOptions.setFormat(nvtt::Format_BC1);
	if (fast)
	{
		compressionOptions.setQuality(nvtt::Quality_Fastest);
	}
	else
	{
		compressionOptions.setQuality(nvtt::Quality_Production);
	}

	nvtt::OutputOptions outputOptions;
	outputOptions.setOutputHeader(false);

	MyOutputHandler outputHandler;
	outputOptions.setOutputHandler(&outputHandler);

	nvtt::Compressor compressor;
	compressor.enableCudaAcceleration(!nocuda);

	FileSystem::createDirectory(outPath);

	Path csvFileName("%s/result.csv", outPath);
	StdOutputStream csvStream(csvFileName);
	TextWriter csvWriter(&csvStream);

	float totalTime = 0;
	float totalRMSE = 0;
	int failedTests = 0;
	float totalDiff = 0;

	for (int i = 0; i < s_fileCount; i++)
	{
		AutoPtr<Image> img( new Image() );

		if (!img->load(s_fileNames[i]))
		{
			printf("Input image '%s' not found.\n", s_fileNames[i]);
			return EXIT_FAILURE;
		}

		inputOptions.setTextureLayout(nvtt::TextureType_2D, img->width(), img->height());
		inputOptions.setMipmapData(img->pixels(), img->width(), img->height());

		printf("Compressing: \t'%s'\n", s_fileNames[i]);

		clock_t start = clock();

		compressor.process(inputOptions, compressionOptions, outputOptions);

		clock_t end = clock();
		printf("  Time: \t%.3f sec\n", float(end-start) / CLOCKS_PER_SEC);
		totalTime += float(end-start);

		AutoPtr<Image> img_out( outputHandler.decompress(nvtt::Format_BC1) );

		Path outputFileName("%s/%s", outPath, s_fileNames[i]);
		outputFileName.stripExtension();
		outputFileName.append(".tga");
		if (!ImageIO::save(outputFileName, img_out.ptr()))
		{
			printf("Error saving file '%s'.\n", outputFileName.str());
		}

		float rmse = rmsError(img.ptr(), img_out.ptr());
		totalRMSE += rmse;

		printf("  RMSE:  \t%.4f\n", rmse);

		// Output csv file
		csvWriter << "\"" << s_fileNames[i] << "\"," << rmse << "\n";

		if (regressPath != NULL)
		{
			Path regressFileName("%s/%s", regressPath, s_fileNames[i]);
			regressFileName.stripExtension();
			regressFileName.append(".tga");

			AutoPtr<Image> img_reg( new Image() );
			if (!img_reg->load(regressFileName.str()))
			{
				printf("Regression image '%s' not found.\n", regressFileName.str());
				return EXIT_FAILURE;
			}

			float rmse_reg = rmsError(img.ptr(), img_reg.ptr());

			float diff = rmse_reg - rmse;
			totalDiff += diff;

			const char * text = "PASSED";
			if (equal(diff, 0)) text = "PASSED";
			else if (diff < 0) {
				text = "FAILED";
				failedTests++;
			}

			printf("  Diff: \t%.4f (%s)\n", diff, text);
		}

		fflush(stdout);
	}

	totalRMSE /= s_fileCount;
	totalDiff /= s_fileCount;

	printf("Total Results:\n");
	printf("  Total Time: \t%.3f sec\n", totalTime / CLOCKS_PER_SEC);
	printf("  Average RMSE:\t%.4f\n", totalRMSE);

	if (regressPath != NULL)
	{
		printf("Regression Results:\n");
		printf("  Diff: %.4f\n", totalDiff);
		printf("  %d/%d tests failed.\n", failedTests, s_fileCount);
	}

	return EXIT_SUCCESS;
}

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

#include <nvtt/nvtt.h>
#include <nvimage/Image.h>
#include <nvimage/ImageIO.h>
#include <nvimage/BlockDXT.h>
#include <nvimage/ColorBlock.h>
#include <nvcore/Ptr.h>
#include <nvcore/Debug.h>
#include <nvcore/StrLib.h>
#include <nvcore/StdStream.h>
#include <nvcore/TextWriter.h>
#include <nvcore/FileSystem.h>

#include <stdlib.h> // free
#include <string.h> // memcpy
#include <time.h> // clock

using namespace nv;

static const char * s_fileNames[] = {
	// Kodak image set
	"kodim01.png",
	"kodim02.png",
	"kodim03.png",
	"kodim04.png",
	"kodim05.png",
	"kodim06.png",
	"kodim07.png",
	"kodim08.png",
	"kodim09.png",
	"kodim10.png",
	"kodim11.png",
	"kodim12.png",
	"kodim13.png",
	"kodim14.png",
	"kodim15.png",
	"kodim16.png",
	"kodim17.png",
	"kodim18.png",
	"kodim19.png",
	"kodim20.png",
	"kodim21.png",
	"kodim22.png",
	"kodim23.png",
	"kodim24.png",
	// Waterloo image set
	"clegg.png",
	"frymire.png",
	"lena.png",
	"monarch.png",
	"peppers.png",
	"sail.png",
	"serrano.png",
	"tulips.png",
	// Epic image set
	"Bradley1.png",
	"Gradient.png",
	"MoreRocks.png",
	"Wall.png",
	"Rainbow.png",
	"Text.png",
};
const int s_fileCount = sizeof(s_fileNames)/sizeof(s_fileNames[0]);

struct MyOutputHandler : public nvtt::OutputHandler
{
	MyOutputHandler() : m_data(NULL), m_ptr(NULL) {}
	~MyOutputHandler()
	{
		free(m_data);
	}

	virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
	{
		m_size = size;
		m_width = width;
		m_height = height;
		free(m_data);
		m_data = (unsigned char *)malloc(size);
		m_ptr = m_data;
	}

	virtual bool writeData(const void * data, int size)
	{
		memcpy(m_ptr, data, size);
		m_ptr += size;
		return true;
	}

	Image * decompress(nvtt::Format format)
	{
		int bw = (m_width + 3) / 4;
		int bh = (m_height + 3) / 4;

		AutoPtr<Image> img( new Image() );
		img->allocate(m_width, m_height);

		if (format == nvtt::Format_BC1)
		{
			BlockDXT1 * block = (BlockDXT1 *)m_data;

			for (int y = 0; y < bh; y++)
			{
				for (int x = 0; x < bw; x++)
				{
					ColorBlock colors;
					block->decodeBlock(&colors);

					for (int yy = 0; yy < 4; yy++)
					{
						for (int xx = 0; xx < 4; xx++)
						{
							Color32 c = colors.color(xx, yy);

							if (x * 4 + xx < m_width && y * 4 + yy < m_height)
							{
								img->pixel(x * 4 + xx, y * 4 + yy) = c;
							}
						}
					}

					block++;
				}
			}
		}

		return img.release();
	}

	int m_size;
	int m_width;
	int m_height;
	unsigned char * m_data;
	unsigned char * m_ptr;
};

float rmsError(const Image * a, const Image * b)
{
	nvCheck(a != NULL);
	nvCheck(b != NULL);
	nvCheck(a->width() == b->width());
	nvCheck(a->height() == b->height());

	int mse = 0;

	const uint count = a->width() * a->height();

	for (uint i = 0; i < count; i++)
	{
		Color32 c0 = a->pixel(i);
		Color32 c1 = b->pixel(i);

		int r = c0.r - c1.r;
		int g = c0.g - c1.g;
		int b = c0.b - c1.b;
		//int a = c0.a - c1.a;

		mse += r * r;
		mse += g * g;
		mse += b * b;
	}

	return sqrtf(float(mse) / count);
}

int main(int argc, char *argv[])
{
	const uint version = nvtt::version();
	const uint major = version / 100;
	const uint minor = version % 100;

	printf("NVIDIA Texture Tools %u.%u - Copyright NVIDIA Corporation 2007 - 2008\n\n", major, minor);

	bool fast = false;
	bool nocuda = false;
	bool showHelp = false;
	const char * outPath = "output";
	const char * regressPath = NULL;

	// Parse arguments.
	for (int i = 1; i < argc; i++)
	{
		if (strcmp("-fast", argv[i]) == 0)
		{
			fast = true;
		}
		else if (strcmp("-nocuda", argv[i]) == 0)
		{
			nocuda = true;
		}
		else if (strcmp("-help", argv[i]) == 0)
		{
			showHelp = true;
		}
		else if (strcmp("-out", argv[i]) == 0)
		{
			if (i+1 < argc && argv[i+1][0] != '-') outPath = argv[i+1];
		}
		else if (strcmp("-regress", argv[i]) == 0)
		{
			if (i+1 < argc && argv[i+1][0] != '-') regressPath = argv[i+1];
		}
	}

	if (showHelp)
	{
		printf("usage: nvtestsuite [options]\n\n");

		printf("Input options:\n");
		printf("  -regress <path>\tRegression directory.\n");

		printf("Compression options:\n");
		printf("  -fast          \tFast compression.\n");
		printf("  -nocuda        \tDo not use cuda compressor.\n");

		printf("Output options:\n");
		printf("  -out <path>    \tOutput directory.\n");

		return 1;
	}

	nvtt::InputOptions inputOptions;
	inputOptions.setMipmapGeneration(false);

	nvtt::CompressionOptions compressionOptions;
	compressionOptions.setFormat(nvtt::Format_BC1);
	if (fast)
	{
		compressionOptions.setQuality(nvtt::Quality_Fastest);
	}
	else
	{
		compressionOptions.setQuality(nvtt::Quality_Production);
	}

	nvtt::OutputOptions outputOptions;
	outputOptions.setOutputHeader(false);

	MyOutputHandler outputHandler;
	outputOptions.setOutputHandler(&outputHandler);

	nvtt::Compressor compressor;
	compressor.enableCudaAcceleration(!nocuda);

	FileSystem::createDirectory(outPath);

	Path csvFileName("%s/result.csv", outPath);
	StdOutputStream csvStream(csvFileName);
	TextWriter csvWriter(&csvStream);

	float totalTime = 0;
	float totalRMSE = 0;
	int failedTests = 0;
	float totalDiff = 0;

	for (int i = 0; i < s_fileCount; i++)
	{
		AutoPtr<Image> img( new Image() );

		if (!img->load(s_fileNames[i]))
		{
			printf("Input image '%s' not found.\n", s_fileNames[i]);
			return EXIT_FAILURE;
		}

		inputOptions.setTextureLayout(nvtt::TextureType_2D, img->width(), img->height());
		inputOptions.setMipmapData(img->pixels(), img->width(), img->height());

		printf("Compressing: \t'%s'\n", s_fileNames[i]);

		clock_t start = clock();

		compressor.process(inputOptions, compressionOptions, outputOptions);

		clock_t end = clock();
		printf("  Time: \t%.3f sec\n", float(end-start) / CLOCKS_PER_SEC);
		totalTime += float(end-start);

		AutoPtr<Image> img_out( outputHandler.decompress(nvtt::Format_BC1) );

		Path outputFileName("%s/%s", outPath, s_fileNames[i]);
		outputFileName.stripExtension();
		outputFileName.append(".tga");
		if (!ImageIO::save(outputFileName, img_out.ptr()))
		{
			printf("Error saving file '%s'.\n", outputFileName.str());
		}

		float rmse = rmsError(img.ptr(), img_out.ptr());
		totalRMSE += rmse;

		printf("  RMSE:  \t%.4f\n", rmse);

		// Output csv file
		csvWriter << "\"" << s_fileNames[i] << "\"," << rmse << "\n";

		if (regressPath != NULL)
		{
			Path regressFileName("%s/%s", regressPath, s_fileNames[i]);
			regressFileName.stripExtension();
			regressFileName.append(".tga");

			AutoPtr<Image> img_reg( new Image() );
			if (!img_reg->load(regressFileName.str()))
			{
				printf("Regression image '%s' not found.\n", regressFileName.str());
				return EXIT_FAILURE;
			}

			float rmse_reg = rmsError(img.ptr(), img_reg.ptr());

			float diff = rmse_reg - rmse;
			totalDiff += diff;

			const char * text = "PASSED";
			if (equal(diff, 0)) text = "PASSED";
			else if (diff < 0) {
				text = "FAILED";
				failedTests++;
			}

			printf("  Diff: \t%.4f (%s)\n", diff, text);
		}

		fflush(stdout);
	}

	totalRMSE /= s_fileCount;
	totalDiff /= s_fileCount;

	printf("Total Results:\n");
	printf("  Total Time: \t%.3f sec\n", totalTime / CLOCKS_PER_SEC);
	printf("  Average RMSE:\t%.4f\n", totalRMSE);

	if (regressPath != NULL)
	{
		printf("Regression Results:\n");
		printf("  Diff: %.4f\n", totalDiff);
		printf("  %d/%d tests failed.\n", failedTests, s_fileCount);
	}

	return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>#include <iostream>
#include "ros/ros.h"
#include "laser_transform_core.h"
#include "pcl_ros/transforms.h"
#include "sensor_msgs/PointCloud2.h"
#include "sensor_msgs/NavSatFix.h"
#include "sensor_msgs/Imu.h"
#include "nav_msgs/Odometry.h"
#include "ip_connection.h"
#include "brick_imu.h"
#include "bricklet_gps.h"
#include "bricklet_industrial_dual_0_20ma.h"

#define HOST "localhost"
//#define HOST "141.56.161.43"
//#define HOST 	"192.168.0.55"
#define PORT 	4223

#define M_PI	3.14159265358979323846  /* pi */
#define DUAL_SENSOR 0
#define DUAL_OPT INDUSTRIAL_DUAL_0_20MA_THRESHOLD_OPTION_GREATER
#define DUAL_MIN 10 * 1000000
#define DUAL_MAX 10 * 1000000
#define DUAL_NUM_OF_MAGNETS 4

/*----------------------------------------------------------------------
 * LaserTransform()
 * Constructor
 *--------------------------------------------------------------------*/

LaserTransform::LaserTransform()
{
  publish_new_pcl = false;
  is_imu_connected = false;
  is_gps_connected = false;
  is_dual020_connected = false;
  start_latitude = 0;
  start_longitude = 0;
  dual020_trigger_cnt = 0;

  laser_orientation.setEuler(0,0,-1.57079633);
}

/*----------------------------------------------------------------------
 * ~LaserTransform
 * Destrucot
 *--------------------------------------------------------------------*/

LaserTransform::~LaserTransform()
{
  if (is_imu_connected)
  {
    imu_leds_off(&imu);
    ipcon_destroy(&ipcon);
  }
}

/*----------------------------------------------------------------------
 * Init()
 * Init the TF-Devices
 *--------------------------------------------------------------------*/

int LaserTransform::init()
{
  // create IP connection
  ipcon_create(&ipcon);

  // register connected callback to "cb_connected"
  ipcon_register_callback(&ipcon,
    IPCON_CALLBACK_CONNECTED,
    (void*)connectedCallback,
    this);

  // register enumeration callback to "cb_enumerate"
  ipcon_register_callback(&ipcon,
    IPCON_CALLBACK_ENUMERATE,
    (void*)enumerateCallback,
    this);

  // connect to brickd
  if(ipcon_connect(&ipcon, HOST, PORT) < 0) {
    std::cout << "could not connect to brickd!" << std::endl;
    return false;
  }
  return 0;
}

/*----------------------------------------------------------------------
 * publishMessage()
 * Publish the message.
 *--------------------------------------------------------------------*/

void LaserTransform::publishMessage(ros::Publisher *pub_message)
{
  if (publish_new_pcl)
  {
    ROS_INFO_STREAM("pcloud out");
    pub_message->publish(pcl_out);
    publish_new_pcl = false;
  }
}

/*----------------------------------------------------------------------
 * odometryCallback()
 * Callback function for filtered odometry.
 *--------------------------------------------------------------------*/
void LaserTransform::odometryCallback(const nav_msgs::Odometry::ConstPtr& msg)
{
  return;
}

/*----------------------------------------------------------------------
 * publishImuMessage()
 * Publish the Imu message.
 *--------------------------------------------------------------------*/

void LaserTransform::publishImuMessage(ros::Publisher *pub_message)
{
  int16_t acc_x, acc_y, acc_z;
  int16_t mag_x, mag_y, mag_z;
  int16_t ang_x, ang_y, ang_z;
  int16_t temp;
  float x = 0.0, y = 0.0, z = 0.0, w = 0.0;
  static uint32_t seq = 0;
  if (is_imu_connected)
  {
    sensor_msgs::Imu imu_msg;

    imu_get_quaternion(&imu, &x, &y, &z, &w);

    imu_get_all_data(&imu, &acc_x, &acc_y, &acc_z, &mag_x, &mag_y,
      &mag_z, &ang_x, &ang_y, &ang_z, &temp);

    // message header
    imu_msg.header.seq = seq;
    imu_msg.header.stamp = ros::Time::now();
    imu_msg.header.frame_id = "world";
    // imu data
    imu_msg.orientation.x = x;
    imu_msg.orientation.y = y;
    imu_msg.orientation.z = z;
    imu_msg.orientation.w = w;

    imu_msg.angular_velocity.x = ang_x;
    imu_msg.angular_velocity.y = ang_y;
    imu_msg.angular_velocity.z = ang_z;

    imu_msg.linear_acceleration.x = acc_x;
    imu_msg.linear_acceleration.y = acc_y;
    imu_msg.linear_acceleration.z = acc_z;

    pub_message->publish(imu_msg);

    seq++;
  }
}

/*----------------------------------------------------------------------
 * publishNavSatFixMessage()
 * Publish the NavSatFix message.
 *--------------------------------------------------------------------*/

void LaserTransform::publishNavSatFixMessage(ros::Publisher *pub_message)
{
  static uint32_t seq = 0;
  uint8_t fix, satellites_view, satellites_used;
  uint16_t pdop, hdop, vdop, epe;
  uint32_t latitude, longitude;
  uint32_t altitude, geoidal_separation;
  char ns, ew;
  if (is_gps_connected)
  {
    // get gps sensor status
    gps_get_status(&gps, &fix, &satellites_view, &satellites_used);

    if (fix == GPS_FIX_NO_FIX)
      return; // No valid data

    gps_get_coordinates(&gps, &latitude, &ns, &longitude, &ew, &pdop,
      &hdop, &vdop, &epe);
    gps_get_altitude(&gps, &altitude, &geoidal_separation);

    sensor_msgs::NavSatFix gps_msg;

    // message header
    gps_msg.header.seq =  seq;
    gps_msg.header.stamp = ros::Time::now();
    gps_msg.header.frame_id = "world";
    // gps status
    gps_msg.status.status = gps_msg.status.STATUS_SBAS_FIX;
    gps_msg.status.service = gps_msg.status.SERVICE_GPS;

    gps_msg.latitude = latitude/1000000.0;
    gps_msg.longitude = longitude/1000000.0;
    //gps_msg.altitude = altitude/100.0;
    gps_msg.altitude = 0.0;
    gps_msg.position_covariance_type = gps_msg.COVARIANCE_TYPE_UNKNOWN;

    pub_message->publish(gps_msg);

    seq++;
  }
}

/*----------------------------------------------------------------------
 * messageCallback()
 * Callback function for subscriber.
 *--------------------------------------------------------------------*/

void LaserTransform::messageCallback(const sensor_msgs::PointCloud2::ConstPtr& msg)
{
  //ROS_INFO_STREAM("pcloud in");
  float xp, yp, zp;
  tf::Transform transform;
  getPosition(&xp, &yp, &zp);
  transform.setOrigin( tf::Vector3(xp, yp, zp) );
  tf::Quaternion q = getQuaternion();
  //tf::Quaternion q2;
  //q2.setEulerZYX(0,0,-1.57079633);
  //transform.setRotation(q2);
  transform.setRotation(laser_orientation);
  sensor_msgs::PointCloud2 pcl_tmp;
  pcl_ros::transformPointCloud("/world2", transform,  *msg, pcl_tmp);
  transform.setRotation(q);
  pcl_ros::transformPointCloud("/world", transform,  pcl_tmp, pcl_out);
  publish_new_pcl = true;
}

/*----------------------------------------------------------------------
 * connectedCallback()
 * Callback function for Tinkerforge ip connected
 *--------------------------------------------------------------------*/

void LaserTransform::connectedCallback(uint8_t connect_reason, void *user_data)
{
  LaserTransform *lt = (LaserTransform*) user_data;
  if (lt->is_imu_connected == false)
    ipcon_enumerate(&(lt->ipcon));
  return;
}

/*----------------------------------------------------------------------
 * enumerateCallback()
 * Callback function for Tinkerforge enumerate
 *--------------------------------------------------------------------*/

void LaserTransform::enumerateCallback(const char *uid, const char *connected_uid,
                  char position, uint8_t hardware_version[3],
                  uint8_t firmware_version[3], uint16_t device_identifier,
                  uint8_t enumeration_type, void *user_data)
{
  LaserTransform *lt = (LaserTransform*) user_data;

  if(enumeration_type == IPCON_ENUMERATION_TYPE_DISCONNECTED)
  {
    return;
  }

  // check if device is an imu
  if(device_identifier == IMU_DEVICE_IDENTIFIER)
  {
    ROS_INFO_STREAM("found IMU with UID:" << uid);
    // Create IMU device object
    imu_create(&(lt->imu), uid, &(lt->ipcon));
    imu_set_convergence_speed(&(lt->imu),0);
    imu_leds_on(&(lt->imu));
    lt->is_imu_connected = true;
  }
  else if (device_identifier == GPS_DEVICE_IDENTIFIER)
  {
    ROS_INFO_STREAM("found GPS with UID:" << uid);
    // Create GPS device object
    gps_create(&(lt->gps), uid, &(lt->ipcon));
    lt->is_gps_connected = true;
  }
  else if (device_identifier == INDUSTRIAL_DUAL_0_20MA_DEVICE_IDENTIFIER)
  {
    ROS_INFO_STREAM("found ID20MA with UID:" << uid);
    // Create IndustrialDual020mA device object
    industrial_dual_0_20ma_create(&(lt->dual020), uid, &(lt->ipcon));
    // Get threshold callbacks with a debounce time of 10 seconds (10000ms)
    industrial_dual_0_20ma_set_debounce_period(&(lt->dual020), 20);

    // Register threshold reached callback to function cb_reached

    industrial_dual_0_20ma_register_callback(&(lt->dual020),
      INDUSTRIAL_DUAL_0_20MA_CALLBACK_CURRENT_REACHED,
      (void*)dual020Callback,
      NULL);

    industrial_dual_0_20ma_set_debounce_period(&(lt->dual020),20);

    industrial_dual_0_20ma_set_current_callback_threshold(&(lt->dual020),
      DUAL_SENSOR, DUAL_OPT, DUAL_MIN, DUAL_MAX);
    lt->is_dual020_connected = true;
  }
}

/*----------------------------------------------------------------------
 * dual020Callback()
 * Callback function for Tinkerforge Industrial Dual 0-20mA Bricklet
 *--------------------------------------------------------------------*/

void LaserTransform::dual020Callback(uint8_t sensor, int32_t current, void *user_data)
{
  LaserTransform *lt = (LaserTransform*) user_data;
  static ros::Time begin = ros::Time::now();
  static int cnt = 0;
  ROS_INFO_STREAM(current);
  //lt->dual020_trigger_cnt++;
  cnt++;

  if ((ros::Time::now().sec - begin.sec) >= 1)
  {
    // calc rounds per minute
    //ROS_INFO_STREAM("Rounds per minute:" << lt->dual020_trigger_cnt / DUAL_NUM_OF_MAGNETS);
    ROS_INFO_STREAM("Rounds per minute:" << cnt / DUAL_NUM_OF_MAGNETS);

    //lt->dual020_trigger_cnt = 0;
	cnt = 0;
    begin = ros::Time::now();
  }
  return;
}

/*----------------------------------------------------------------------
 * getQuaternion()
 * get IMU quaternion
 *--------------------------------------------------------------------*/

tf::Quaternion LaserTransform::getQuaternion()
{
  float x = 0.0, y = 0.0, z = 0.0, w = 0.0;

  if (is_imu_connected)
    imu_get_quaternion(&imu, &x, &y, &z, &w);

  tf::Quaternion q(x, y*-1, z, w);
  return q;
}

/*----------------------------------------------------------------------
 * getVelocity()
 * get Velocity
 *--------------------------------------------------------------------*/

int LaserTransform::getVelocity(float *velocity)
{
  *velocity = 0.0;
  return true;
}

/*----------------------------------------------------------------------
 * getPosition()
 * get Position
 *--------------------------------------------------------------------*/

int LaserTransform::getPosition(float *x_pos, float *y_pos, float *z_pos)
{
  *x_pos = 0;
  *y_pos = 0;
  *z_pos = 0;
  return true;
}
<commit_msg>add gps log change function names<commit_after>#include <iostream>
#include <sstream>
#include <fstream>
#include <cmath>
#include "ros/ros.h"
#include "laser_transform_core.h"
#include "pcl_ros/transforms.h"
#include "sensor_msgs/PointCloud2.h"
#include "sensor_msgs/NavSatFix.h"
#include "sensor_msgs/Imu.h"
#include "nav_msgs/Odometry.h"
#include <geodesy/wgs84.h>
#include <geodesy/utm.h>
#include <geometry_msgs/Point.h>
#include "ip_connection.h"
#include "brick_imu.h"
#include "bricklet_gps.h"
#include "bricklet_industrial_dual_0_20ma.h"

#define HOST "localhost"
//#define HOST "141.56.161.43"
//#define HOST 	"192.168.0.55"
#define PORT 	4223

#define DUAL_SENSOR1 0
#define DUAL_SENSOR2 1
#define DUAL_OPT INDUSTRIAL_DUAL_0_20MA_THRESHOLD_OPTION_GREATER
#define DUAL_MIN 10 * 1000000
#define DUAL_MAX 10 * 1000000
#define DUAL_NUM_OF_MAGNETS 1

#define GPS_LOGFILE true
#define LOGFILE_PATH "/home/vmuser/logs/"

/*----------------------------------------------------------------------
 * LaserTransform()
 * Constructor
 *--------------------------------------------------------------------*/

LaserTransform::LaserTransform()
{
  publish_new_pcl = false;
  is_imu_connected = false;
  is_gps_connected = false;
  is_dual020_connected = false;
  start_latitude = 0;
  start_longitude = 0;
  velocity = 0.0;
  dual020_trigger_cnt_c1 = 0;
  dual020_trigger_cnt_c2 = 0;
  imu_convergence_speed = 0;

  xpos = ypos = 0;
  // set laser scanner orientation to imu orientation
  laser_orientation.setRPY(-90*M_PI/180.0,0,0);

  // open gps log file
  if (GPS_LOGFILE)
  {
    std::stringstream ss;

    time_t t;
    struct tm *ts;
    char buff[80];

    // build filename
    t = time(NULL);
    ts = localtime(&t);

    strftime(buff, 80, "gps_log_%Y_%m_%d-%H_%M_%S.txt", ts);
    ss << LOGFILE_PATH << buff;

    gps_log.open(ss.str().c_str(), std::ios::out);
  }
}

/*----------------------------------------------------------------------
 * ~LaserTransform
 * Destructor
 *--------------------------------------------------------------------*/

LaserTransform::~LaserTransform()
{
  if (is_imu_connected)
  {
    imu_leds_off(&imu);
    ipcon_destroy(&ipcon);
  }
  // close gps logfile
  if (gps_log.is_open())
    gps_log.close();
}

/*----------------------------------------------------------------------
 * Init()
 * Init the TF-Devices
 *--------------------------------------------------------------------*/

int LaserTransform::init()
{
  // create IP connection
  ipcon_create(&ipcon);

  // register connected callback to "cb_connected"
  ipcon_register_callback(&ipcon,
    IPCON_CALLBACK_CONNECTED,
    (void*)connectedCallback,
    this);

  // register enumeration callback to "cb_enumerate"
  ipcon_register_callback(&ipcon,
    IPCON_CALLBACK_ENUMERATE,
    (void*)enumerateCallback,
    this);

  // connect to brickd
  if(ipcon_connect(&ipcon, HOST, PORT) < 0) {
    std::cout << "could not connect to brickd!" << std::endl;
    return false;
  }
  return 0;
}

/*----------------------------------------------------------------------
 * publishPclMessage()
 * Publish the transformed plc data.
 *--------------------------------------------------------------------*/

void LaserTransform::publishPclMessage(ros::Publisher *pub_message)
{
  if (publish_new_pcl)
  {
    pub_message->publish(pcl_out);
    publish_new_pcl = false;
  }
}

/*----------------------------------------------------------------------
 * odometryCallback()
 * Callback function for filtered odometry.
 *--------------------------------------------------------------------*/
void LaserTransform::odometryCallback(const nav_msgs::Odometry::ConstPtr& msg)
{
  //msg.pose.pose.point.x
  return;
}

/*----------------------------------------------------------------------
 * publishImuMessage()
 * Publish the Imu message.
 *--------------------------------------------------------------------*/

void LaserTransform::publishImuMessage(ros::Publisher *pub_message)
{
  int16_t acc_x, acc_y, acc_z;
  int16_t mag_x, mag_y, mag_z;
  int16_t ang_x, ang_y, ang_z;
  int16_t temp;
  float x = 0.0, y = 0.0, z = 0.0, w = 0.0;
  static uint32_t seq = 0;
  if (is_imu_connected)
  {
    sensor_msgs::Imu imu_msg;

    imu_get_quaternion(&imu, &x, &y, &z, &w);

    imu_get_all_data(&imu, &acc_x, &acc_y, &acc_z, &mag_x, &mag_y,
      &mag_z, &ang_x, &ang_y, &ang_z, &temp);
    /*
    float yaw   =  atan2(2.0*(x*y + w*z), pow(w,2)+pow(x,2)-pow(y,2)-pow(z,2));
    float pitch = -asin(2.0*(w*y - x*z));
    float roll  = -atan2(2.0*(y*z + w*x), -(pow(w,2)-pow(x,2)-pow(y,2)+pow(z,2)));
1
    tf::Quaternion q;
    q.setEuler(yaw, pitch, roll);
    */
    // message header
    imu_msg.header.seq = seq;
    imu_msg.header.stamp = ros::Time::now();
    imu_msg.header.frame_id = "/world";
    // imu data
    /*
    imu_msg.orientation.x = q.getAxis()[0];
    imu_msg.orientation.y = q.getAxis()[1];
    imu_msg.orientation.z = q.getAxis()[2];
    imu_msg.orientation.w = q.getW();
    */
    imu_msg.orientation.x = x;
    imu_msg.orientation.y = y;
    imu_msg.orientation.z = z;
    imu_msg.orientation.w = w;

    imu_msg.orientation_covariance[0] = -1;

    imu_msg.angular_velocity.x = ang_x;
    imu_msg.angular_velocity.y = ang_y;
    imu_msg.angular_velocity.z = ang_z;
    imu_msg.angular_velocity_covariance[0] = -1;

    imu_msg.linear_acceleration.x = acc_x;
    imu_msg.linear_acceleration.y = acc_y;
    imu_msg.linear_acceleration.z = acc_z;
    imu_msg.linear_acceleration_covariance[0] = -1;

    pub_message->publish(imu_msg);

    seq++;
  }
}

/*----------------------------------------------------------------------
 * publishNavSatFixMessage()
 * Publish the NavSatFix message.
 *--------------------------------------------------------------------*/

void LaserTransform::publishNavSatFixMessage(ros::Publisher *pub_message)
{
  static uint32_t seq = 0;
  uint8_t fix, satellites_view, satellites_used;
  uint16_t pdop, hdop, vdop, epe;
  uint32_t latitude, longitude;
  uint32_t altitude, geoidal_separation;
  char ns, ew;
  if (is_gps_connected)
  {
    // get gps sensor status
    gps_get_status(&gps, &fix, &satellites_view, &satellites_used);

    if (fix != GPS_FIX_3D_FIX)
      return; // No valid data

    gps_get_coordinates(&gps, &latitude, &ns, &longitude, &ew, &pdop,
      &hdop, &vdop, &epe);
    gps_get_altitude(&gps, &altitude, &geoidal_separation);

    sensor_msgs::NavSatFix gps_msg;

    // message header
    gps_msg.header.seq =  seq;
    gps_msg.header.stamp = ros::Time::now();
    gps_msg.header.frame_id = "/world";
    // gps status
    gps_msg.status.status = gps_msg.status.STATUS_SBAS_FIX;
    gps_msg.status.service = gps_msg.status.SERVICE_GPS;

    gps_msg.latitude = latitude/1000000.0;
    gps_msg.longitude = longitude/1000000.0;
    gps_msg.altitude = altitude/100.0;
    gps_msg.position_covariance_type = gps_msg.COVARIANCE_TYPE_UNKNOWN;

    if (gps_log.is_open() && GPS_LOGFILE)
    {
      std::string separator = "|";
      gps_log << ros::Time::now().sec;
      gps_log << gps_log << separator;
      gps_log << gps_msg.latitude;
      gps_log << separator;
      gps_log << gps_msg.longitude;
      gps_log << separator;
      gps_log << gps_msg.altitude;
      gps_log << std::endl;
    }

    geographic_msgs::GeoPoint ll;
    // create UTM from point
    ll = geodesy::toMsg(gps_msg);
    geodesy::UTMPoint pt;
    geodesy::fromMsg(ll,pt);
    if (xpos == 0 && ypos == 0)
    {
      xpos = pt.easting;
      ypos = pt.northing;
    }
    else
    {
      //ROS_INFO_STREAM("COORDS_1:" << pt.easting << "::" << pt.northing);
      //ROS_INFO_STREAM("COORDS_2:" << xpos << "::" << ypos);

      //std::cout << "COORDS_3:" << (int)(xpos-pt.easting) << "::" << (int)(ypos-pt.northing) << std::endl;
      //ROS_INFO_STREAM("COORDS_3:" << (int)xpos-pt.easting << "::" << (int)ypos-pt.northing);
    }
    pub_message->publish(gps_msg);

    seq++;
  }
}

/*----------------------------------------------------------------------
 * pclCallback()
 * Callback function for laser scanner pcl.
 *--------------------------------------------------------------------*/

void LaserTransform::pclCallback(const sensor_msgs::PointCloud2::ConstPtr& msg)
{
  //ROS_INFO_STREAM("pcloud in");
  float xp, yp, zp;
  tf::Transform transform;
  getPosition(&xp, &yp, &zp);
  transform.setOrigin( tf::Vector3(xp, yp, zp) );
  tf::Quaternion q = getQuaternion();
  transform.setRotation(laser_orientation);
  sensor_msgs::PointCloud2 pcl_tmp;
  pcl_ros::transformPointCloud("/world2", transform,  *msg, pcl_tmp);
  transform.setRotation(q);
  pcl_ros::transformPointCloud("/world", transform,  pcl_tmp, pcl_out);
  publish_new_pcl = true;
}

/*----------------------------------------------------------------------
 * connectedCallback()
 * Callback function for Tinkerforge ip connected
 *--------------------------------------------------------------------*/

void LaserTransform::connectedCallback(uint8_t connect_reason, void *user_data)
{
  LaserTransform *lt = (LaserTransform*) user_data;
  if (lt->is_imu_connected == false)
    ipcon_enumerate(&(lt->ipcon));
  return;
}

/*----------------------------------------------------------------------
 * enumerateCallback()
 * Callback function for Tinkerforge enumerate
 *--------------------------------------------------------------------*/

void LaserTransform::enumerateCallback(const char *uid, const char *connected_uid,
                  char position, uint8_t hardware_version[3],
                  uint8_t firmware_version[3], uint16_t device_identifier,
                  uint8_t enumeration_type, void *user_data)
{
  LaserTransform *lt = (LaserTransform*) user_data;

  if(enumeration_type == IPCON_ENUMERATION_TYPE_DISCONNECTED)
  {
    return;
  }

  // check if device is an imu
  if(device_identifier == IMU_DEVICE_IDENTIFIER)
  {
    ROS_INFO_STREAM("found IMU with UID:" << uid);
    // Create IMU device object
    imu_create(&(lt->imu), uid, &(lt->ipcon));
    imu_set_convergence_speed(&(lt->imu),5);
    imu_leds_on(&(lt->imu));
    lt->is_imu_connected = true;
  }
  else if (device_identifier == GPS_DEVICE_IDENTIFIER)
  {
    ROS_INFO_STREAM("found GPS with UID:" << uid);
    // Create GPS device object
    gps_create(&(lt->gps), uid, &(lt->ipcon));
    lt->is_gps_connected = true;
  }
  else if (device_identifier == INDUSTRIAL_DUAL_0_20MA_DEVICE_IDENTIFIER)
  {
    ROS_INFO_STREAM("found ID20MA with UID:" << uid);
    // Create IndustrialDual020mA device object
    industrial_dual_0_20ma_create(&(lt->dual020), uid, &(lt->ipcon));
    // Get threshold callbacks with a debounce time of 20ms
    industrial_dual_0_20ma_set_debounce_period(&(lt->dual020), lt->imu_convergence_speed);

    // Register threshold reached callback to function cb_reached

    industrial_dual_0_20ma_register_callback(&(lt->dual020),
      INDUSTRIAL_DUAL_0_20MA_CALLBACK_CURRENT_REACHED,
      (void*)dual020Callback,
      lt);

    industrial_dual_0_20ma_set_current_callback_threshold(&(lt->dual020),
      DUAL_SENSOR1, DUAL_OPT, DUAL_MIN, DUAL_MAX);
    industrial_dual_0_20ma_set_current_callback_threshold(&(lt->dual020),
      DUAL_SENSOR2, DUAL_OPT, DUAL_MIN, DUAL_MAX);

    // set sample rate for sensors
    industrial_dual_0_20ma_set_sample_rate(&(lt->dual020),
      INDUSTRIAL_DUAL_0_20MA_SAMPLE_RATE_240_SPS);
    lt->is_dual020_connected = true;
  }
}

/*----------------------------------------------------------------------
 * dual020Callback()
 * Callback function for Tinkerforge Industrial Dual 0-20mA Bricklet
 *--------------------------------------------------------------------*/

void LaserTransform::dual020Callback(uint8_t sensor, int32_t current, void *user_data)
{
  LaserTransform *lt = (LaserTransform*) user_data;
  static ros::Time begin = ros::Time::now();
  static int cnt_c1 = 0, cnt_c2 = 0;
  //ROS_INFO_STREAM(current);

  if (sensor == 0)
  {
    cnt_c1++;
    //lt->dual020_trigger_cnt_c1++;
  }
  else
  {
    cnt_c2++;
    //lt->dual020_trigger_cnt_c2++;
  }

  if ((ros::Time::now().sec - begin.sec) >= 1)
  {
    // calc rounds per minute
    //ROS_INFO_STREAM("Rounds per minute:" << lt->dual020_trigger_cnt / DUAL_NUM_OF_MAGNETS);
    ROS_INFO_STREAM("Sensor 1:" << cnt_c1 / DUAL_NUM_OF_MAGNETS << " U/Sek" << "::" << cnt_c1);
    ROS_INFO_STREAM("Sensor 2:" << cnt_c2 / DUAL_NUM_OF_MAGNETS << " U/Sek" << "::" << cnt_c2);

    //lt->dual020_trigger_cnt_c1 = 0;
    //lt->dual020_trigger_cnt_c2 = 0;
	cnt_c1 = cnt_c2 = 0;
    begin = ros::Time::now();
  }
  return;
}

/*----------------------------------------------------------------------
 * getQuaternion()
 * get IMU quaternion
 *--------------------------------------------------------------------*/

tf::Quaternion LaserTransform::getQuaternion()
{
  float x = 0.0, y = 0.0, z = 0.0, w = 0.0;

  if (is_imu_connected)
    imu_get_quaternion(&imu, &x, &y, &z, &w);

  //-------
  float yaw   =  atan2(2.0*(x*y + w*z), pow(w,2)+pow(x,2)-pow(y,2)-pow(z,2));
  float pitch = -asin(2.0*(w*y - x*z));
  float roll  = -atan2(2.0*(y*z + w*x), -(pow(w,2)-pow(x,2)-pow(y,2)+pow(z,2)));
  std::cout << "y:" << rad2deg(yaw) << ":: p:" << rad2deg(pitch) << ":: r:" << rad2deg(roll) << std::endl;
  //-------

  tf::Quaternion q;
  q.setEuler(yaw, pitch, roll);
  //tf::Quaternion q(x, y, z, w);
  //tf::Quaternion q(x, y*-1, z, w);
  return q;
}

/*----------------------------------------------------------------------
 * getVelocity()
 * get Velocity
 *--------------------------------------------------------------------*/

int LaserTransform::getVelocity(float *velocity)
{
  *velocity = 0.0;
  return true;
}

/*----------------------------------------------------------------------
 * getPosition()
 * get Position
 *--------------------------------------------------------------------*/

int LaserTransform::getPosition(float *x_pos, float *y_pos, float *z_pos)
{
  *x_pos = 0;
  *y_pos = 0;
  *z_pos = 0;
  return true;
}
<|endoftext|>