<commit_before>//===-- JavaFormatterFunctions.cpp-------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "JavaFormatterFunctions.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/Symbol/JavaASTContext.h"

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;

namespace
{

class JavaArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
    JavaArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) :
        SyntheticChildrenFrontEnd(*valobj_sp)
    {
        if (valobj_sp)
            Update();
    }

    size_t
    CalculateNumChildren() override
    {
        ValueObjectSP valobj = GetDereferencedValueObject();
        if (!valobj)
            return 0;

        CompilerType type = valobj->GetCompilerType();
        uint32_t size = JavaASTContext::CalculateArraySize(type, *valobj);
        if (size == UINT32_MAX)
            return 0;
        return size;
    }

    lldb::ValueObjectSP
    GetChildAtIndex(size_t idx) override
    {
        ValueObjectSP valobj = GetDereferencedValueObject();
        if (!valobj)
            return nullptr;

        ProcessSP process_sp = valobj->GetProcessSP();
        if (!process_sp)
            return nullptr;

        CompilerType type = valobj->GetCompilerType();
        CompilerType element_type = type.GetArrayElementType();
        lldb::addr_t address = valobj->GetAddressOf() + JavaASTContext::CalculateArrayElementOffset(type, idx);

        Error error;
        size_t byte_size = element_type.GetByteSize(nullptr);
        DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0));
        size_t bytes_read = process_sp->ReadMemory(address, buffer_sp->GetBytes(), byte_size, error);
        if (error.Fail() || byte_size != bytes_read)
            return nullptr;

        StreamString name;
        name.Printf("[%" PRIu64 "]", (uint64_t)idx);
        DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
        return CreateValueObjectFromData(name.GetData(), data, valobj->GetExecutionContextRef(),
                                         element_type);
    }

    bool
    Update() override
    {
        return false;
    }

    bool
    MightHaveChildren() override
    {
        return true;
    }

    size_t
    GetIndexOfChildWithName(const ConstString &name) override
    {
        return ExtractIndexFromString(name.GetCString());
    }

private:
    ValueObjectSP
    GetDereferencedValueObject()
    {
        if (!m_backend.IsPointerOrReferenceType())
            m_backend.GetSP();

        Error error;
        return m_backend.Dereference(error);
    }
};

} // end of anonymous namespace

bool
lldb_private::formatters::JavaStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &opts)
{
    if (valobj.IsPointerOrReferenceType())
    {
        Error error;
        ValueObjectSP deref = valobj.Dereference(error);
        if (error.Fail())
            return false;
        return JavaStringSummaryProvider(*deref, stream, opts);
    }

    ProcessSP process_sp = valobj.GetProcessSP();
    if (!process_sp)
        return false;

    ConstString data_name("value");
    ConstString length_name("count");

    ValueObjectSP length_sp = valobj.GetChildMemberWithName(length_name, true);
    ValueObjectSP data_sp = valobj.GetChildMemberWithName(data_name, true);
    if (!data_sp || !length_sp)
        return false;

    bool success = false;
    uint64_t length = length_sp->GetValueAsUnsigned(0, &success);
    if (!success)
        return false;

    if (length == 0)
    {
        stream.Printf("\"\"");
        return true;
    }
    lldb::addr_t valobj_addr = data_sp->GetAddressOf();

    StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
    options.SetLocation(valobj_addr);
    options.SetProcessSP(process_sp);
    options.SetStream(&stream);
    options.SetSourceSize(length);
    options.SetNeedsZeroTermination(false);
    options.SetLanguage(eLanguageTypeJava);

    if (StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16>(options))
        return true;

    stream.Printf("Summary Unavailable");
    return true;
}

bool
lldb_private::formatters::JavaArraySummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
{
    if (valobj.IsPointerOrReferenceType())
    {
        Error error;
        ValueObjectSP deref = valobj.Dereference(error);
        if (error.Fail())
            return false;
        return JavaArraySummaryProvider(*deref, stream, options);
    }

    CompilerType type = valobj.GetCompilerType();
    uint32_t size = JavaASTContext::CalculateArraySize(type, valobj);
    if (size == UINT32_MAX)
        return false;
    stream.Printf("[%u]{...}", size);
    return true;
}

SyntheticChildrenFrontEnd*
lldb_private::formatters::JavaArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
    return valobj_sp ? new JavaArraySyntheticFrontEnd(valobj_sp) : nullptr;
}
<commit_msg>Fix JavaArraySyntheticFrontEnd for non-reference ValueObject.<commit_after>//===-- JavaFormatterFunctions.cpp-------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "JavaFormatterFunctions.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/Symbol/JavaASTContext.h"

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;

namespace
{

class JavaArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
    JavaArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) :
        SyntheticChildrenFrontEnd(*valobj_sp)
    {
        if (valobj_sp)
            Update();
    }

    size_t
    CalculateNumChildren() override
    {
        ValueObjectSP valobj = GetDereferencedValueObject();
        if (!valobj)
            return 0;

        CompilerType type = valobj->GetCompilerType();
        uint32_t size = JavaASTContext::CalculateArraySize(type, *valobj);
        if (size == UINT32_MAX)
            return 0;
        return size;
    }

    lldb::ValueObjectSP
    GetChildAtIndex(size_t idx) override
    {
        ValueObjectSP valobj = GetDereferencedValueObject();
        if (!valobj)
            return nullptr;

        ProcessSP process_sp = valobj->GetProcessSP();
        if (!process_sp)
            return nullptr;

        CompilerType type = valobj->GetCompilerType();
        CompilerType element_type = type.GetArrayElementType();
        lldb::addr_t address = valobj->GetAddressOf() + JavaASTContext::CalculateArrayElementOffset(type, idx);

        Error error;
        size_t byte_size = element_type.GetByteSize(nullptr);
        DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0));
        size_t bytes_read = process_sp->ReadMemory(address, buffer_sp->GetBytes(), byte_size, error);
        if (error.Fail() || byte_size != bytes_read)
            return nullptr;

        StreamString name;
        name.Printf("[%" PRIu64 "]", (uint64_t)idx);
        DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
        return CreateValueObjectFromData(name.GetData(), data, valobj->GetExecutionContextRef(),
                                         element_type);
    }

    bool
    Update() override
    {
        return false;
    }

    bool
    MightHaveChildren() override
    {
        return true;
    }

    size_t
    GetIndexOfChildWithName(const ConstString &name) override
    {
        return ExtractIndexFromString(name.GetCString());
    }

private:
    ValueObjectSP
    GetDereferencedValueObject()
    {
        if (!m_backend.IsPointerOrReferenceType())
            return m_backend.GetSP();

        Error error;
        return m_backend.Dereference(error);
    }
};

} // end of anonymous namespace

bool
lldb_private::formatters::JavaStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &opts)
{
    if (valobj.IsPointerOrReferenceType())
    {
        Error error;
        ValueObjectSP deref = valobj.Dereference(error);
        if (error.Fail())
            return false;
        return JavaStringSummaryProvider(*deref, stream, opts);
    }

    ProcessSP process_sp = valobj.GetProcessSP();
    if (!process_sp)
        return false;

    ConstString data_name("value");
    ConstString length_name("count");

    ValueObjectSP length_sp = valobj.GetChildMemberWithName(length_name, true);
    ValueObjectSP data_sp = valobj.GetChildMemberWithName(data_name, true);
    if (!data_sp || !length_sp)
        return false;

    bool success = false;
    uint64_t length = length_sp->GetValueAsUnsigned(0, &success);
    if (!success)
        return false;

    if (length == 0)
    {
        stream.Printf("\"\"");
        return true;
    }
    lldb::addr_t valobj_addr = data_sp->GetAddressOf();

    StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
    options.SetLocation(valobj_addr);
    options.SetProcessSP(process_sp);
    options.SetStream(&stream);
    options.SetSourceSize(length);
    options.SetNeedsZeroTermination(false);
    options.SetLanguage(eLanguageTypeJava);

    if (StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16>(options))
        return true;

    stream.Printf("Summary Unavailable");
    return true;
}

bool
lldb_private::formatters::JavaArraySummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
{
    if (valobj.IsPointerOrReferenceType())
    {
        Error error;
        ValueObjectSP deref = valobj.Dereference(error);
        if (error.Fail())
            return false;
        return JavaArraySummaryProvider(*deref, stream, options);
    }

    CompilerType type = valobj.GetCompilerType();
    uint32_t size = JavaASTContext::CalculateArraySize(type, valobj);
    if (size == UINT32_MAX)
        return false;
    stream.Printf("[%u]{...}", size);
    return true;
}

SyntheticChildrenFrontEnd*
lldb_private::formatters::JavaArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
    return valobj_sp ? new JavaArraySyntheticFrontEnd(valobj_sp) : nullptr;
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <fclaw2d_forestclaw.h>
#include <fclaw2d_clawpatch.h>
#include <fclaw2d_clawpatch.hpp>

#include <ClawPatch.H>

void fclaw2d_clawpatch_link_app(fclaw_app_t* app)
{
    ClawPatch::app = app;
}

void fclaw2d_clawpatch_link_global (fclaw2d_global_t * global)
{
    ClawPatch::global = global;
}

ClawPatch* fclaw2d_clawpatch_get_cp(fclaw2d_patch_t* this_patch)

{
    return fclaw2d_patch_get_cp(this_patch);
}

/* ------------------------------------------------------------------
   Repartition and rebuild new domains, or construct initial domain
 -------------------------------------------------------------------- */
void fclaw2d_clawpatch_define(fclaw2d_domain_t* domain,
                              fclaw2d_patch_t *this_patch,
                              int blockno, int patchno)
{
    const amr_options_t *gparms = get_domain_parms(domain);
    int level = this_patch->level;

    ClawPatch *cp = fclaw2d_patch_new_cp(this_patch);
    cp->define(this_patch->xlower,
               this_patch->ylower,
               this_patch->xupper,
               this_patch->yupper,
               blockno,
               level,
               gparms);

    fclaw2d_domain_data_t *ddata = get_domain_data(domain);
    ++ddata->count_set_clawpatch;
}

void fclaw2d_clawpatch_grid_data(fclaw2d_domain_t* domain,
                                 fclaw2d_patch_t* this_patch,
                                 int* mx, int* my, int* mbc,
                                 double* xlower, double* ylower,
                                 double* dx, double* dy)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *mx = cp->mx();
    *my = cp->my();
    *mbc = cp->mbc();
    *xlower = cp->xlower();
    *ylower = cp->ylower();
    *dx = cp->dx();
    *dy = cp->dy();
}

void fclaw2d_clawpatch_metric_data(fclaw2d_domain_t* domain,
                                   fclaw2d_patch_t* this_patch,
                                   double **xp, double **yp, double **zp,
                                   double **xd, double **yd, double **zd,
                                   double **area)
{
    /* Declared as a friend in ClawPatch.H */
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *xp = cp->xp();
    *yp = cp->yp();
    *zp = cp->zp();
    *xd = cp->xd();
    *yd = cp->yd();
    *zd = cp->zd();
    *area = cp->area();
}

double* fclaw2d_clawpatch_get_area(fclaw2d_domain_t* domain,
                                   fclaw2d_patch_t* this_patch)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    return cp->area();
}

void fclaw2d_clawpatch_soln_data(fclaw2d_domain_t* domain,
                                 fclaw2d_patch_t* this_patch,
                                 double **q, int* meqn)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *q = cp->q();
    *meqn = cp->meqn();
}

double *fclaw2d_clawpatch_get_q(fclaw2d_domain_t* domain,
                                fclaw2d_patch_t* this_patch)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    return cp->q();
}

void fclaw2d_clawpatch_timesync_data(fclaw2d_domain_t* domain,
                                     fclaw2d_patch_t* this_patch,
                                     fclaw_bool time_interp,
                                     double **q, int* meqn)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *q = cp->q_time_sync(time_interp);
    *meqn = cp->meqn();
}

double *fclaw2d_clawpatch_get_q_timesync(fclaw2d_domain_t* domain,
                                         fclaw2d_patch_t* this_patch,
                                         int time_interp)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    return cp->q_time_sync(time_interp);
}

void fclaw2d_clawpatch_save_current_step(fclaw2d_domain_t* domain,
                                         fclaw2d_patch_t* this_patch)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    cp->save_current_step();
}

void fclaw2d_clawpatch_metric_data2(fclaw2d_domain_t* domain, fclaw2d_patch_t* this_patch,
                                    double **xnormals, double **ynormals,
                                    double **xtangents, double **ytangents,
                                    double **surfnormals,
                                    double **edgelengths, double **curvature)
{
    /* or just call the member functions? */
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *xnormals    = cp->xface_normals();
    *ynormals    = cp->yface_normals();
    *xtangents   = cp->xface_tangents();
    *ytangents   = cp->yface_tangents();
    *surfnormals = cp->surf_normals();
    *curvature   = cp->curvature();
    *edgelengths = cp->edge_lengths();
}

int* fclaw2d_clawpatch_corner_count(fclaw2d_domain_t* domain,
                                   fclaw2d_patch_t* this_patch)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    return cp->block_corner_count();
}

void fclaw2d_clawpatch_build_cb(fclaw2d_domain_t *domain,
                                fclaw2d_patch_t *this_patch,
                                int this_block_idx,
                                int this_patch_idx,
                                void *user)
{
    fclaw2d_vtable_t vt;
    vt = fclaw2d_get_vtable(domain);

    fclaw2d_clawpatch_define(domain,this_patch,this_block_idx,this_patch_idx);

    if (vt.patch_setup != NULL)
    {
        vt.patch_setup(domain,this_patch,this_block_idx,this_patch_idx);
    }
}

void fclaw2d_clawpatch_pack_cb(fclaw2d_domain_t *domain,
                               fclaw2d_patch_t *this_patch,
                               int this_block_idx,
                               int this_patch_idx,
                               void *user)
{
    fclaw2d_block_t *this_block = &domain->blocks[this_block_idx];
    int patch_num = this_block->num_patches_before + this_patch_idx;
    double* patch_data = (double*) ((void**)user)[patch_num];

    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    FCLAW_ASSERT(cp != NULL);
    cp->pack_griddata(patch_data);
}

void fclaw2d_clawpatch_unpack_ghost(fclaw2d_domain_t* domain,
                                    fclaw2d_patch_t* this_patch,
                                    int this_block_idx, int this_patch_idx,
                                    double *qdata, fclaw_bool time_interp)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    if (time_interp)
        cp->unpack_griddata_time_interpolated(qdata);
    else
        cp->unpack_griddata(qdata);
}

void fclaw2d_clawpatch_unpack_cb(fclaw2d_domain_t *domain,
                                 fclaw2d_patch_t *this_patch,
                                 int this_block_idx,
                                 int this_patch_idx,
                                 void *user)
{
    fclaw2d_block_t *this_block = &domain->blocks[this_block_idx];
    int patch_num = this_block->num_patches_before + this_patch_idx;
    double* patch_data = (double*) ((void**)user)[patch_num];

    fclaw_bool time_interp = fclaw_false;
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);

    if (time_interp)
        cp->unpack_griddata_time_interpolated(patch_data);
    else
        cp->unpack_griddata(patch_data);

}

void fclaw2d_clawpatch_delete_cp(fclaw2d_domain_t* domain,
                                 fclaw2d_patch_t* this_patch)
{
    fclaw2d_patch_delete_cp(this_patch);

    fclaw2d_domain_data_t *ddata = get_domain_data(domain);
    ++ddata->count_delete_clawpatch;
}

size_t fclaw2d_clawpatch_pack_size(fclaw2d_domain_t* domain)
{
    const amr_options_t *gparms = get_domain_parms(domain);
    int mx = gparms->mx;
    int my = gparms->my;
    int mbc = gparms->mbc;
    int meqn = gparms->meqn;
    size_t size = (2*mbc + mx)*(2*mbc+my)*meqn;
    return size*sizeof(double);
}

void fclaw2d_clawpatch_setup_timeinterp(fclaw2d_domain_t* domain,
                                        fclaw2d_patch_t *this_patch,
                                        double alpha)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    cp->setup_for_time_interpolation(alpha);
}
<commit_msg>Rearranged routines<commit_after>/*
Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <fclaw2d_forestclaw.h>
#include <fclaw2d_clawpatch.h>
#include <fclaw2d_clawpatch.hpp>

#include <ClawPatch.H>

void fclaw2d_clawpatch_link_app(fclaw_app_t* app)
{
    ClawPatch::app = app;
}

void fclaw2d_clawpatch_link_global (fclaw2d_global_t * global)
{
    ClawPatch::global = global;
}

ClawPatch* fclaw2d_clawpatch_get_cp(fclaw2d_patch_t* this_patch)

{
    return fclaw2d_patch_get_cp(this_patch);
}

void fclaw2d_clawpatch_grid_data(fclaw2d_domain_t* domain,
                                 fclaw2d_patch_t* this_patch,
                                 int* mx, int* my, int* mbc,
                                 double* xlower, double* ylower,
                                 double* dx, double* dy)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *mx = cp->mx();
    *my = cp->my();
    *mbc = cp->mbc();
    *xlower = cp->xlower();
    *ylower = cp->ylower();
    *dx = cp->dx();
    *dy = cp->dy();
}

void fclaw2d_clawpatch_metric_data(fclaw2d_domain_t* domain,
                                   fclaw2d_patch_t* this_patch,
                                   double **xp, double **yp, double **zp,
                                   double **xd, double **yd, double **zd,
                                   double **area)
{
    /* Declared as a friend in ClawPatch.H */
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *xp = cp->xp();
    *yp = cp->yp();
    *zp = cp->zp();
    *xd = cp->xd();
    *yd = cp->yd();
    *zd = cp->zd();
    *area = cp->area();
}

double* fclaw2d_clawpatch_get_area(fclaw2d_domain_t* domain,
                                   fclaw2d_patch_t* this_patch)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    return cp->area();
}

void fclaw2d_clawpatch_soln_data(fclaw2d_domain_t* domain,
                                 fclaw2d_patch_t* this_patch,
                                 double **q, int* meqn)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *q = cp->q();
    *meqn = cp->meqn();
}

double *fclaw2d_clawpatch_get_q(fclaw2d_domain_t* domain,
                                fclaw2d_patch_t* this_patch)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    return cp->q();
}

void fclaw2d_clawpatch_setup_timeinterp(fclaw2d_domain_t* domain,
                                        fclaw2d_patch_t *this_patch,
                                        double alpha)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    cp->setup_for_time_interpolation(alpha);
}

void fclaw2d_clawpatch_timesync_data(fclaw2d_domain_t* domain,
                                     fclaw2d_patch_t* this_patch,
                                     fclaw_bool time_interp,
                                     double **q, int* meqn)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *q = cp->q_time_sync(time_interp);
    *meqn = cp->meqn();
}

double *fclaw2d_clawpatch_get_q_timesync(fclaw2d_domain_t* domain,
                                         fclaw2d_patch_t* this_patch,
                                         int time_interp)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    return cp->q_time_sync(time_interp);
}

void fclaw2d_clawpatch_save_current_step(fclaw2d_domain_t* domain,
                                         fclaw2d_patch_t* this_patch)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    cp->save_current_step();
}

void fclaw2d_clawpatch_metric_data2(fclaw2d_domain_t* domain,
                                    fclaw2d_patch_t* this_patch,
                                    double **xnormals, double **ynormals,
                                    double **xtangents, double **ytangents,
                                    double **surfnormals,
                                    double **edgelengths, double **curvature)
{
    /* or just call the member functions? */
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    *xnormals    = cp->xface_normals();
    *ynormals    = cp->yface_normals();
    *xtangents   = cp->xface_tangents();
    *ytangents   = cp->yface_tangents();
    *surfnormals = cp->surf_normals();
    *curvature   = cp->curvature();
    *edgelengths = cp->edge_lengths();
}

int* fclaw2d_clawpatch_corner_count(fclaw2d_domain_t* domain,
                                   fclaw2d_patch_t* this_patch)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    return cp->block_corner_count();
}

/* ------------------------------------------------------------------
   Repartition and rebuild new domains, or construct initial domain
 -------------------------------------------------------------------- */
void fclaw2d_clawpatch_define(fclaw2d_domain_t* domain,
                              fclaw2d_patch_t *this_patch,
                              int blockno, int patchno)
{
    const amr_options_t *gparms = get_domain_parms(domain);
    int level = this_patch->level;

    ClawPatch *cp = fclaw2d_patch_new_cp(this_patch);
    cp->define(this_patch->xlower,
               this_patch->ylower,
               this_patch->xupper,
               this_patch->yupper,
               blockno,
               level,
               gparms);

    fclaw2d_domain_data_t *ddata = get_domain_data(domain);
    ++ddata->count_set_clawpatch;
}

void fclaw2d_clawpatch_build_cb(fclaw2d_domain_t *domain,
                                fclaw2d_patch_t *this_patch,
                                int this_block_idx,
                                int this_patch_idx,
                                void *user)
{
    fclaw2d_vtable_t vt;
    vt = fclaw2d_get_vtable(domain);

    fclaw2d_clawpatch_define(domain,this_patch,this_block_idx,this_patch_idx);

    if (vt.patch_setup != NULL)
    {
        vt.patch_setup(domain,this_patch,this_block_idx,this_patch_idx);
    }
}

void fclaw2d_clawpatch_pack_cb(fclaw2d_domain_t *domain,
                               fclaw2d_patch_t *this_patch,
                               int this_block_idx,
                               int this_patch_idx,
                               void *user)
{
    fclaw2d_block_t *this_block = &domain->blocks[this_block_idx];
    int patch_num = this_block->num_patches_before + this_patch_idx;
    double* patch_data = (double*) ((void**)user)[patch_num];

    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    FCLAW_ASSERT(cp != NULL);
    cp->pack_griddata(patch_data);
}

void fclaw2d_clawpatch_unpack_ghost(fclaw2d_domain_t* domain,
                                    fclaw2d_patch_t* this_patch,
                                    int this_block_idx,
                                    int this_patch_idx,
                                    double *qdata, fclaw_bool time_interp)
{
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);
    if (time_interp)
        cp->unpack_griddata_time_interpolated(qdata);
    else
        cp->unpack_griddata(qdata);
}

void fclaw2d_clawpatch_unpack_cb(fclaw2d_domain_t *domain,
                                 fclaw2d_patch_t *this_patch,
                                 int this_block_idx,
                                 int this_patch_idx,
                                 void *user)
{
    fclaw2d_block_t *this_block = &domain->blocks[this_block_idx];
    int patch_num = this_block->num_patches_before + this_patch_idx;
    double* patch_data = (double*) ((void**)user)[patch_num];

    fclaw_bool time_interp = fclaw_false;
    ClawPatch *cp = fclaw2d_clawpatch_get_cp(this_patch);

    if (time_interp)
        cp->unpack_griddata_time_interpolated(patch_data);
    else
        cp->unpack_griddata(patch_data);

}

void fclaw2d_clawpatch_delete_cp(fclaw2d_domain_t* domain,
                                 fclaw2d_patch_t* this_patch)
{
    fclaw2d_patch_delete_cp(this_patch);

    fclaw2d_domain_data_t *ddata = get_domain_data(domain);
    ++ddata->count_delete_clawpatch;
}

size_t fclaw2d_clawpatch_pack_size(fclaw2d_domain_t* domain)
{
    const amr_options_t *gparms = get_domain_parms(domain);
    int mx = gparms->mx;
    int my = gparms->my;
    int mbc = gparms->mbc;
    int meqn = gparms->meqn;
    size_t size = (2*mbc + mx)*(2*mbc+my)*meqn;
    return size*sizeof(double);
}
<|endoftext|>


<commit_before>/*
    OpenDeck MIDI platform firmware
    Copyright (C) 2015-2017 Igor Petrovic

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

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

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

#include "interface/Interface.h"

SysEx sysEx;
MIDI midi;

void initSysEx()
{
    sysEx.addBlocks(DB_BLOCKS);

    sysExSection section;

    {
        //MIDI block

        //midi feature section
        section.numberOfParameters = MIDI_FEATURES;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_MIDI, section);

        //midi channel section
        section.numberOfParameters = MIDI_CHANNELS;
        section.minValue = 1;
        section.maxValue = 16;

        sysEx.addSection(DB_BLOCK_MIDI, section);
    }

    {
        //button block

        //type section
        section.numberOfParameters = MAX_NUMBER_OF_BUTTONS+MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = BUTTON_TYPES-1;

        sysEx.addSection(DB_BLOCK_BUTTON, section);

        //midi message type section
        section.numberOfParameters = MAX_NUMBER_OF_BUTTONS+MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = BUTTON_MESSAGE_TYPES-1;

        sysEx.addSection(DB_BLOCK_BUTTON, section);

        //midi id section
        section.numberOfParameters = MAX_NUMBER_OF_BUTTONS+MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_BUTTON, section);
    }

    {
        //encoder block

        //encoder enabled section
        section.numberOfParameters = MAX_NUMBER_OF_ENCODERS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_ENCODER, section);

        //encoder inverted section
        section.numberOfParameters = MAX_NUMBER_OF_ENCODERS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_ENCODER, section);

        //encoding mode section
        section.numberOfParameters = MAX_NUMBER_OF_ENCODERS;
        section.minValue = 0;
        section.maxValue = ENCODING_MODES-1;

        sysEx.addSection(DB_BLOCK_ENCODER, section);

        //midi id section
        section.numberOfParameters = MAX_NUMBER_OF_ENCODERS;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_ENCODER, section);
    }

    {
        //analog block

        //analog enabled section
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //analog inverted section
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //analog type section
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = ANALOG_TYPES-1;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //midi id section
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //lower cc limit
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //upper cc limit
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_ANALOG, section);
    }

    {
        //led block

        //hardware parameters section
        section.numberOfParameters = LED_HARDWARE_PARAMETERS;
        section.minValue = 0;
        section.maxValue = 0;

        sysEx.addSection(DB_BLOCK_LED, section);

        //activation note section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_LED, section);

        //rgb enabled section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_LED, section);

        //local led control enabled section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_LED, section);

        //led color section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = LED_COLORS-1;

        sysEx.addSection(DB_BLOCK_LED, section);

        //led blink section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_LED, section);
    }
}

void globalInit()
{
    #if defined(BOARD_OPEN_DECK) || defined(BOARD_A_LEO)
    midi.setUSBMIDIstate(true);
    #endif

    #if defined(BOARD_OPEN_DECK) || defined(BOARD_A_MEGA)
    midi.setDINMIDIstate(true);
    #endif

    midi.setOneByteParseDINstate(true);

    database.init();
    board.init();

    midi.setInputChannel(database.read(DB_BLOCK_MIDI, midiChannelSection, inputChannel));
    initSysEx();

    //enable global interrupts
    sei();

    leds.init();
}

bool onCustom(uint8_t value)
{
    switch(value)
    {
        case FIRMWARE_VERSION_STRING:
        sysEx.addToResponse(1);
        sysEx.addToResponse(0);
        sysEx.addToResponse(0);
        return true;

        case HARDWARE_VERSION_STRING:
        sysEx.addToResponse(HARDWARE_VERSION_MAJOR);
        sysEx.addToResponse(HARDWARE_VERSION_MINOR);
        sysEx.addToResponse(HARDWARE_VERSION_REVISION);
        return true;

        case MAX_COMPONENTS_STRING:
        sysEx.addToResponse(MAX_NUMBER_OF_BUTTONS+MAX_NUMBER_OF_ANALOG);
        sysEx.addToResponse(MAX_NUMBER_OF_ENCODERS);
        sysEx.addToResponse(MAX_NUMBER_OF_ANALOG);
        sysEx.addToResponse(MAX_NUMBER_OF_LEDS);
        return true;

        case REBOOT_APP_STRING:
        leds.setAllOff();
        wait_ms(2500);
        board.reboot(rebootApp);
        return true;

        case REBOOT_BTLDR_STRING:
        leds.setAllOff();
        wait_ms(2500);
        board.reboot(rebootBtldr);
        return true;

        case FACTORY_RESET_STRING:
        leds.setAllOff();
        wait_ms(1500);
        database.factoryReset(initPartial);
        board.reboot(rebootApp);
        return true;
    }

    return false;
}

sysExParameter_t onGet(uint8_t block, uint8_t section, uint16_t index)
{
    switch(block)
    {
        case DB_BLOCK_LED:
        switch(section)
        {
            case ledColorSection:
            return leds.getColor(index);

            case ledBlinkSection:
            return leds.getBlinkState(index);

            default:
            return database.read(block, section, index);
        }
        break;

        default:
        return database.read(block, section, index);
    }
}

bool onSet(uint8_t block, uint8_t section, uint16_t index, sysExParameter_t newValue)
{
    bool returnValue = true;
    //check this block manually
    if (block != DB_BLOCK_LED)
        returnValue = database.update(block, section, index, newValue);

    if (returnValue)
    {
        //special checks
        switch(block)
        {
            case DB_BLOCK_ANALOG:
            if (section == analogTypeSection)
                analog.debounceReset(index);
            break;

            case DB_BLOCK_MIDI:
            if (section == midiFeatureSection)
            {
                if (index == midiFeatureRunningStatus)
                    midi.setRunningStatusState(newValue);
                else if (index == midiFeatureStandardNoteOff)
                    newValue ? midi.setNoteOffMode(noteOffType_standardNoteOff) : midi.setNoteOffMode(noteOffType_noteOnZeroVel);
            }
            break;

            case DB_BLOCK_LED:
            switch(section)
            {
                case ledColorSection:
                //no writing to database
                leds.setColor(index, (ledColor_t)newValue);
                break;

                case ledBlinkSection:
                //no writing to database
                leds.setBlinkState(index, newValue);
                break;

                case ledHardwareParameterSection:
                //this entire section needs specific value check
                switch(index)
                {
                    case ledHwParameterBlinkTime:
                    if ((newValue < BLINK_TIME_MIN) || (newValue > BLINK_TIME_MAX))
                        return false;
                    leds.setBlinkTime(newValue);
                    break;

                    case ledHwParameterFadeTime:
                    if ((newValue < FADE_TIME_MIN) || (newValue > FADE_TIME_MAX))
                        return false;
                    #ifdef BOARD_OPEN_DECK
                    leds.setFadeTime(newValue);
                    #endif
                    break;

                    case ledHwParameterStartUpRoutine:
                    if (newValue > 1)
                        return false;
                    break;
                }
                //values are ok - write
                database.update(block, section, index, newValue);
                break;

                case ledRGBenabledSection:
                //make sure to turn all three leds off before setting new state
                leds.setColor(board.getRGBaddress(index, rgb_R), colorOff);
                leds.setColor(board.getRGBaddress(index, rgb_G), colorOff);
                leds.setColor(board.getRGBaddress(index, rgb_B), colorOff);
                //write rgb enabled bit to three leds
                database.update(block, section, board.getRGBaddress(index, rgb_R), newValue);
                database.update(block, section, board.getRGBaddress(index, rgb_G), newValue);
                database.update(block, section, board.getRGBaddress(index, rgb_B), newValue);
                break;

                default:
                database.update(block, section, index, newValue);
                break;
            }
            break;

            default:
            break;
        }
    }

    return returnValue;
}

void writeSysEx(uint8_t sysExArray[], uint8_t arraysize)
{
    midi.sendSysEx(arraysize, sysExArray, true);
}

int main()
{
    globalInit();

    sysEx.setHandleGet(onGet);
    sysEx.setHandleSet(onSet);
    sysEx.setHandleCustomRequest(onCustom);
    sysEx.setHandleSysExWrite(writeSysEx);

    sysEx.addCustomRequest(FIRMWARE_VERSION_STRING);
    sysEx.addCustomRequest(HARDWARE_VERSION_STRING);
    sysEx.addCustomRequest(MAX_COMPONENTS_STRING);
    sysEx.addCustomRequest(REBOOT_APP_STRING);
    sysEx.addCustomRequest(REBOOT_BTLDR_STRING);
    sysEx.addCustomRequest(FACTORY_RESET_STRING);

    while(1)
    {
        #if defined(BOARD_A_LEO) || defined(BOARD_OPEN_DECK)
        if (midi.read(usbInterface))
        {
            //new message on usb
            midiMessageType_t messageType = midi.getType(usbInterface);
            uint8_t data1 = midi.getData1(usbInterface);
            uint8_t data2 = midi.getData2(usbInterface);

            switch(messageType)
            {
                case midiMessageSystemExclusive:
                sysEx.handleMessage(midi.getSysExArray(usbInterface), midi.getSysExArrayLength(usbInterface));
                break;

                case midiMessageNoteOn:
                //we're using received note data to control LED color
                leds.noteToState(data1, data2);
                break;

                case midiMessageNoteOff:
                //always turn led off when note off is received
                leds.noteToState(data1, 0);
                break;

                case midiMessageControlChange:
                //control change is used to control led blinking
                leds.ccToBlink(data1, data2);
                break;

                default:
                break;
            }
        }
        #endif

        #ifndef BOARD_A_MEGA
        if (midi.getDINMIDIstate())
        {
            //check for incoming MIDI messages on USART
            if (!database.read(DB_BLOCK_MIDI, midiFeatureSection, midiFeatureUSBconvert))
            {
                midi.read(dinInterface);
                midiMessageType_t messageType = midi.getType(dinInterface);
                uint8_t data1 = midi.getData1(dinInterface);
                uint8_t data2 = midi.getData2(dinInterface);

                switch(messageType)
                {
                    case midiMessageNoteOff:
                    case midiMessageNoteOn:
                    leds.noteToState(data1, data2);
                    break;

                    default:
                    break;
                }
            }
            else
            {
                //dump everything from MIDI in to USB MIDI out
                midi.read(dinInterface, THRU_FULL_USB);
            }
        }
        #endif

        #ifdef BOARD_A_MEGA
        if (midi.read(dinInterface))
        {
            midiMessageType_t messageType = midi.getType(dinInterface);
            uint8_t data1 = midi.getData1(dinInterface);
            uint8_t data2 = midi.getData2(dinInterface);

            switch(messageType)
            {
                case midiMessageSystemExclusive:
                sysEx.handleMessage(midi.getSysExArray(dinInterface), midi.getSysExArrayLength(dinInterface));
                break;

                case midiMessageNoteOn:
                //we're using received note data to control LED color
                leds.noteToState(data1, data2);
                break;

                case midiMessageNoteOff:
                //always turn led off when note off is received
                leds.noteToState(data1, 0);
                break;

                case midiMessageControlChange:
                //control change is used to control led blinking
                leds.ccToBlink(data1, data2);
                break;

                default:
                break;
            }
        }
        #endif

        //digitalInput.update();
        //analog.update();
        //leds.update();
    }
}
<commit_msg>uncomment stuff<commit_after>/*
    OpenDeck MIDI platform firmware
    Copyright (C) 2015-2017 Igor Petrovic

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

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

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

#include "interface/Interface.h"

SysEx sysEx;
MIDI midi;

void initSysEx()
{
    sysEx.addBlocks(DB_BLOCKS);

    sysExSection section;

    {
        //MIDI block

        //midi feature section
        section.numberOfParameters = MIDI_FEATURES;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_MIDI, section);

        //midi channel section
        section.numberOfParameters = MIDI_CHANNELS;
        section.minValue = 1;
        section.maxValue = 16;

        sysEx.addSection(DB_BLOCK_MIDI, section);
    }

    {
        //button block

        //type section
        section.numberOfParameters = MAX_NUMBER_OF_BUTTONS+MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = BUTTON_TYPES-1;

        sysEx.addSection(DB_BLOCK_BUTTON, section);

        //midi message type section
        section.numberOfParameters = MAX_NUMBER_OF_BUTTONS+MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = BUTTON_MESSAGE_TYPES-1;

        sysEx.addSection(DB_BLOCK_BUTTON, section);

        //midi id section
        section.numberOfParameters = MAX_NUMBER_OF_BUTTONS+MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_BUTTON, section);
    }

    {
        //encoder block

        //encoder enabled section
        section.numberOfParameters = MAX_NUMBER_OF_ENCODERS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_ENCODER, section);

        //encoder inverted section
        section.numberOfParameters = MAX_NUMBER_OF_ENCODERS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_ENCODER, section);

        //encoding mode section
        section.numberOfParameters = MAX_NUMBER_OF_ENCODERS;
        section.minValue = 0;
        section.maxValue = ENCODING_MODES-1;

        sysEx.addSection(DB_BLOCK_ENCODER, section);

        //midi id section
        section.numberOfParameters = MAX_NUMBER_OF_ENCODERS;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_ENCODER, section);
    }

    {
        //analog block

        //analog enabled section
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //analog inverted section
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //analog type section
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = ANALOG_TYPES-1;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //midi id section
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //lower cc limit
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_ANALOG, section);

        //upper cc limit
        section.numberOfParameters = MAX_NUMBER_OF_ANALOG;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_ANALOG, section);
    }

    {
        //led block

        //hardware parameters section
        section.numberOfParameters = LED_HARDWARE_PARAMETERS;
        section.minValue = 0;
        section.maxValue = 0;

        sysEx.addSection(DB_BLOCK_LED, section);

        //activation note section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = 127;

        sysEx.addSection(DB_BLOCK_LED, section);

        //rgb enabled section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_LED, section);

        //local led control enabled section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_LED, section);

        //led color section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = LED_COLORS-1;

        sysEx.addSection(DB_BLOCK_LED, section);

        //led blink section
        section.numberOfParameters = MAX_NUMBER_OF_LEDS;
        section.minValue = 0;
        section.maxValue = 1;

        sysEx.addSection(DB_BLOCK_LED, section);
    }
}

void globalInit()
{
    #if defined(BOARD_OPEN_DECK) || defined(BOARD_A_LEO)
    midi.setUSBMIDIstate(true);
    #endif

    #if defined(BOARD_OPEN_DECK) || defined(BOARD_A_MEGA)
    midi.setDINMIDIstate(true);
    #endif

    midi.setOneByteParseDINstate(true);

    database.init();
    board.init();

    midi.setInputChannel(database.read(DB_BLOCK_MIDI, midiChannelSection, inputChannel));
    initSysEx();

    //enable global interrupts
    sei();

    leds.init();
}

bool onCustom(uint8_t value)
{
    switch(value)
    {
        case FIRMWARE_VERSION_STRING:
        sysEx.addToResponse(1);
        sysEx.addToResponse(0);
        sysEx.addToResponse(0);
        return true;

        case HARDWARE_VERSION_STRING:
        sysEx.addToResponse(HARDWARE_VERSION_MAJOR);
        sysEx.addToResponse(HARDWARE_VERSION_MINOR);
        sysEx.addToResponse(HARDWARE_VERSION_REVISION);
        return true;

        case MAX_COMPONENTS_STRING:
        sysEx.addToResponse(MAX_NUMBER_OF_BUTTONS+MAX_NUMBER_OF_ANALOG);
        sysEx.addToResponse(MAX_NUMBER_OF_ENCODERS);
        sysEx.addToResponse(MAX_NUMBER_OF_ANALOG);
        sysEx.addToResponse(MAX_NUMBER_OF_LEDS);
        return true;

        case REBOOT_APP_STRING:
        leds.setAllOff();
        wait_ms(2500);
        board.reboot(rebootApp);
        return true;

        case REBOOT_BTLDR_STRING:
        leds.setAllOff();
        wait_ms(2500);
        board.reboot(rebootBtldr);
        return true;

        case FACTORY_RESET_STRING:
        leds.setAllOff();
        wait_ms(1500);
        database.factoryReset(initPartial);
        board.reboot(rebootApp);
        return true;
    }

    return false;
}

sysExParameter_t onGet(uint8_t block, uint8_t section, uint16_t index)
{
    switch(block)
    {
        case DB_BLOCK_LED:
        switch(section)
        {
            case ledColorSection:
            return leds.getColor(index);

            case ledBlinkSection:
            return leds.getBlinkState(index);

            default:
            return database.read(block, section, index);
        }
        break;

        default:
        return database.read(block, section, index);
    }
}

bool onSet(uint8_t block, uint8_t section, uint16_t index, sysExParameter_t newValue)
{
    bool returnValue = true;
    //check this block manually
    if (block != DB_BLOCK_LED)
        returnValue = database.update(block, section, index, newValue);

    if (returnValue)
    {
        //special checks
        switch(block)
        {
            case DB_BLOCK_ANALOG:
            if (section == analogTypeSection)
                analog.debounceReset(index);
            break;

            case DB_BLOCK_MIDI:
            if (section == midiFeatureSection)
            {
                if (index == midiFeatureRunningStatus)
                    midi.setRunningStatusState(newValue);
                else if (index == midiFeatureStandardNoteOff)
                    newValue ? midi.setNoteOffMode(noteOffType_standardNoteOff) : midi.setNoteOffMode(noteOffType_noteOnZeroVel);
            }
            break;

            case DB_BLOCK_LED:
            switch(section)
            {
                case ledColorSection:
                //no writing to database
                leds.setColor(index, (ledColor_t)newValue);
                break;

                case ledBlinkSection:
                //no writing to database
                leds.setBlinkState(index, newValue);
                break;

                case ledHardwareParameterSection:
                //this entire section needs specific value check
                switch(index)
                {
                    case ledHwParameterBlinkTime:
                    if ((newValue < BLINK_TIME_MIN) || (newValue > BLINK_TIME_MAX))
                        return false;
                    leds.setBlinkTime(newValue);
                    break;

                    case ledHwParameterFadeTime:
                    if ((newValue < FADE_TIME_MIN) || (newValue > FADE_TIME_MAX))
                        return false;
                    #ifdef BOARD_OPEN_DECK
                    leds.setFadeTime(newValue);
                    #endif
                    break;

                    case ledHwParameterStartUpRoutine:
                    if (newValue > 1)
                        return false;
                    break;
                }
                //values are ok - write
                database.update(block, section, index, newValue);
                break;

                case ledRGBenabledSection:
                //make sure to turn all three leds off before setting new state
                leds.setColor(board.getRGBaddress(index, rgb_R), colorOff);
                leds.setColor(board.getRGBaddress(index, rgb_G), colorOff);
                leds.setColor(board.getRGBaddress(index, rgb_B), colorOff);
                //write rgb enabled bit to three leds
                database.update(block, section, board.getRGBaddress(index, rgb_R), newValue);
                database.update(block, section, board.getRGBaddress(index, rgb_G), newValue);
                database.update(block, section, board.getRGBaddress(index, rgb_B), newValue);
                break;

                default:
                database.update(block, section, index, newValue);
                break;
            }
            break;

            default:
            break;
        }
    }

    return returnValue;
}

void writeSysEx(uint8_t sysExArray[], uint8_t arraysize)
{
    midi.sendSysEx(arraysize, sysExArray, true);
}

int main()
{
    globalInit();

    sysEx.setHandleGet(onGet);
    sysEx.setHandleSet(onSet);
    sysEx.setHandleCustomRequest(onCustom);
    sysEx.setHandleSysExWrite(writeSysEx);

    sysEx.addCustomRequest(FIRMWARE_VERSION_STRING);
    sysEx.addCustomRequest(HARDWARE_VERSION_STRING);
    sysEx.addCustomRequest(MAX_COMPONENTS_STRING);
    sysEx.addCustomRequest(REBOOT_APP_STRING);
    sysEx.addCustomRequest(REBOOT_BTLDR_STRING);
    sysEx.addCustomRequest(FACTORY_RESET_STRING);

    while(1)
    {
        #if defined(BOARD_A_LEO) || defined(BOARD_OPEN_DECK)
        if (midi.read(usbInterface))
        {
            //new message on usb
            midiMessageType_t messageType = midi.getType(usbInterface);
            uint8_t data1 = midi.getData1(usbInterface);
            uint8_t data2 = midi.getData2(usbInterface);

            switch(messageType)
            {
                case midiMessageSystemExclusive:
                sysEx.handleMessage(midi.getSysExArray(usbInterface), midi.getSysExArrayLength(usbInterface));
                break;

                case midiMessageNoteOn:
                //we're using received note data to control LED color
                leds.noteToState(data1, data2);
                break;

                case midiMessageNoteOff:
                //always turn led off when note off is received
                leds.noteToState(data1, 0);
                break;

                case midiMessageControlChange:
                //control change is used to control led blinking
                leds.ccToBlink(data1, data2);
                break;

                default:
                break;
            }
        }
        #endif

        #ifndef BOARD_A_MEGA
        if (midi.getDINMIDIstate())
        {
            //check for incoming MIDI messages on USART
            if (!database.read(DB_BLOCK_MIDI, midiFeatureSection, midiFeatureUSBconvert))
            {
                midi.read(dinInterface);
                midiMessageType_t messageType = midi.getType(dinInterface);
                uint8_t data1 = midi.getData1(dinInterface);
                uint8_t data2 = midi.getData2(dinInterface);

                switch(messageType)
                {
                    case midiMessageNoteOff:
                    case midiMessageNoteOn:
                    leds.noteToState(data1, data2);
                    break;

                    default:
                    break;
                }
            }
            else
            {
                //dump everything from MIDI in to USB MIDI out
                midi.read(dinInterface, THRU_FULL_USB);
            }
        }
        #endif

        #ifdef BOARD_A_MEGA
        if (midi.read(dinInterface))
        {
            midiMessageType_t messageType = midi.getType(dinInterface);
            uint8_t data1 = midi.getData1(dinInterface);
            uint8_t data2 = midi.getData2(dinInterface);

            switch(messageType)
            {
                case midiMessageSystemExclusive:
                sysEx.handleMessage(midi.getSysExArray(dinInterface), midi.getSysExArrayLength(dinInterface));
                break;

                case midiMessageNoteOn:
                //we're using received note data to control LED color
                leds.noteToState(data1, data2);
                break;

                case midiMessageNoteOff:
                //always turn led off when note off is received
                leds.noteToState(data1, 0);
                break;

                case midiMessageControlChange:
                //control change is used to control led blinking
                leds.ccToBlink(data1, data2);
                break;

                default:
                break;
            }
        }
        #endif

        digitalInput.update();
        analog.update();
        leds.update();
    }
}
<|endoftext|>


<commit_before>#include "source/extensions/filters/http/grpc_stats/grpc_stats_filter.h"

#include "envoy/extensions/filters/http/grpc_stats/v3/config.pb.h"
#include "envoy/extensions/filters/http/grpc_stats/v3/config.pb.validate.h"
#include "envoy/registry/registry.h"

#include "source/common/grpc/codec.h"
#include "source/common/grpc/common.h"
#include "source/common/grpc/context_impl.h"
#include "source/common/runtime/runtime_impl.h"
#include "source/common/stats/symbol_table_impl.h"
#include "source/extensions/filters/http/common/pass_through_filter.h"

namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace GrpcStats {

namespace {

// A map from gRPC service/method name to symbolized stat names for the service/method.
//
// The expected usage pattern is that the map is populated once, and can then be queried lock-free
// as long as it isn't being modified.
class GrpcServiceMethodToRequestNamesMap {
public:
public:
  // Construct a map populated with the services/methods in method_list.
  GrpcServiceMethodToRequestNamesMap(Stats::SymbolTable& symbol_table,
                                     const envoy::config::core::v3::GrpcMethodList& method_list)
      : stat_name_pool_(symbol_table), map_(populate(method_list)) {}

  absl::optional<Grpc::Context::RequestStatNames>
  lookup(const Grpc::Common::RequestNames& request_names) const {
    auto it = map_.find(request_names);
    if (it != map_.end()) {
      return it->second;
    }

    return {};
  }

private:
  using OwningKey = std::tuple<std::string, std::string>;
  using ViewKey = Grpc::Common::RequestNames;

  class MapHash {
  private:
    // Use the same type for hashing all variations to ensure the same hash value from all source
    // types.
    using ViewTuple = std::tuple<absl::string_view, absl::string_view>;
    static uint64_t hash(const ViewTuple& key) { return absl::Hash<ViewTuple>()(key); }

  public:
    using is_transparent = void; // NOLINT(readability-identifier-naming)

    uint64_t operator()(const OwningKey& key) const { return hash(key); }
    uint64_t operator()(const ViewKey& key) const {
      return hash(ViewTuple(key.service_, key.method_));
    }
  };

  struct MapEq {
    using is_transparent = void; // NOLINT(readability-identifier-naming)
    bool operator()(const OwningKey& left, const OwningKey& right) const { return left == right; }
    bool operator()(const OwningKey& left, const ViewKey& right) const {
      return left == std::make_tuple(right.service_, right.method_);
    }
  };
  using MapType = absl::flat_hash_map<OwningKey, Grpc::Context::RequestStatNames, MapHash, MapEq>;

  // Helper for generating a populated MapType so that `map_` can be const.
  MapType populate(const envoy::config::core::v3::GrpcMethodList& method_list) {
    MapType map;
    for (const auto& service : method_list.services()) {
      Stats::StatName stat_name_service = stat_name_pool_.add(service.name());

      for (const auto& method_name : service.method_names()) {
        Stats::StatName stat_name_method = stat_name_pool_.add(method_name);
        map[OwningKey(service.name(), method_name)] =
            Grpc::Context::RequestStatNames{stat_name_service, stat_name_method};
      }
    }
    return map;
  }

  Stats::StatNamePool stat_name_pool_;
  const MapType map_;
};

struct Config {
  Config(const envoy::extensions::filters::http::grpc_stats::v3::FilterConfig& proto_config,
         Server::Configuration::FactoryContext& context)
      : context_(context.grpcContext()), emit_filter_state_(proto_config.emit_filter_state()),
        enable_upstream_stats_(proto_config.enable_upstream_stats()) {

    switch (proto_config.per_method_stat_specifier_case()) {
    case envoy::extensions::filters::http::grpc_stats::v3::FilterConfig::
        PER_METHOD_STAT_SPECIFIER_NOT_SET:
    case envoy::extensions::filters::http::grpc_stats::v3::FilterConfig::kStatsForAllMethods:
      if (proto_config.has_stats_for_all_methods()) {
        stats_for_all_methods_ = proto_config.stats_for_all_methods().value();
      } else {
        // Default for when "grpc_stats_filter_enable_stats_for_all_methods_by_default" isn't
        // set.
        //
        // This will flip to false after one release.
        const bool runtime_feature_default = false;

        const char* runtime_key = "envoy.deprecated_features.grpc_stats_filter_enable_"
                                  "stats_for_all_methods_by_default";

        stats_for_all_methods_ = context.runtime().snapshot().deprecatedFeatureEnabled(
            runtime_key, runtime_feature_default);

        if (stats_for_all_methods_) {
          ENVOY_LOG_MISC(warn,
                         "Using deprecated default value for "
                         "'envoy.extensions.filters.http.grpc_stats.v3.FilterConfig.stats_for_all_"
                         "methods'. The default for this field will become false in a future "
                         "release. To retain this behavior, set this field to true in your "
                         "configuration. A short-term workaround of setting runtime configuration "
                         "{} to true can be used if the configuration cannot be changed.",
                         runtime_key);
        }
      }
      break;

    case envoy::extensions::filters::http::grpc_stats::v3::FilterConfig::
        kIndividualMethodStatsAllowlist:
      allowlist_.emplace(context.scope().symbolTable(),
                         proto_config.individual_method_stats_allowlist());
      break;
    }
  }
  Grpc::Context& context_;
  const bool emit_filter_state_;
  const bool enable_upstream_stats_;
  bool stats_for_all_methods_{false};
  absl::optional<GrpcServiceMethodToRequestNamesMap> allowlist_;
};
using ConfigConstSharedPtr = std::shared_ptr<const Config>;

class GrpcStatsFilter : public Http::PassThroughFilter {
public:
  GrpcStatsFilter(ConfigConstSharedPtr config) : config_(config) {}

  Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers, bool) override {
    grpc_request_ = Grpc::Common::isGrpcRequestHeaders(headers);
    if (grpc_request_) {
      cluster_ = decoder_callbacks_->clusterInfo();
      if (cluster_) {
        if (config_->stats_for_all_methods_) {
          // Get dynamically-allocated Context::RequestStatNames from the context.
          request_names_ = config_->context_.resolveDynamicServiceAndMethod(headers.Path());
          do_stat_tracking_ = request_names_.has_value();
        } else {
          // This case handles both proto_config.stats_for_all_methods() == false,
          // and proto_config.has_individual_method_stats_allowlist(). This works
          // because proto_config.stats_for_all_methods() == false results in
          // an empty allowlist, which exactly matches the behavior specified for
          // this configuration.
          //
          // Resolve the service and method to a string_view, then get
          // the Context::RequestStatNames out of the pre-allocated list that
          // can be produced with the allowlist being present.
          absl::optional<Grpc::Common::RequestNames> request_names =
              Grpc::Common::resolveServiceAndMethod(headers.Path());

          if (request_names) {
            // Do stat tracking as long as this looks like a grpc service/method,
            // even if it isn't in the allowlist. Things not in the allowlist
            // are counted with a stat with no service/method in the name.
            do_stat_tracking_ = true;

            // If the entry is not found in the allowlist, this will return
            // an empty optional; each of the `charge` functions on the context
            // will interpret an empty optional for this value to mean that the
            // service.method prefix on the stat should be omitted.
            if (config_->allowlist_) {
              request_names_ = config_->allowlist_->lookup(*request_names);
            }
          }
        }
      }
    }
    return Http::FilterHeadersStatus::Continue;
  }

  Http::FilterDataStatus decodeData(Buffer::Instance& data, bool) override {
    if (grpc_request_) {
      uint64_t delta = request_counter_.inspect(data);
      if (delta > 0) {
        maybeWriteFilterState();
        if (doStatTracking()) {
          config_->context_.chargeRequestMessageStat(*cluster_, request_names_, delta);
        }
      }
    }
    return Http::FilterDataStatus::Continue;
  }

  Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap& headers,
                                          bool end_stream) override {
    grpc_response_ = Grpc::Common::isGrpcResponseHeaders(headers, end_stream);
    if (doStatTracking()) {
      config_->context_.chargeStat(*cluster_, Grpc::Context::Protocol::Grpc, request_names_,
                                   headers.GrpcStatus());
      if (end_stream) {
        maybeChargeUpstreamStat();
      }
    }
    return Http::FilterHeadersStatus::Continue;
  }

  Http::FilterDataStatus encodeData(Buffer::Instance& data, bool) override {
    if (grpc_response_) {
      uint64_t delta = response_counter_.inspect(data);
      if (delta > 0) {
        maybeWriteFilterState();
        if (doStatTracking()) {
          config_->context_.chargeResponseMessageStat(*cluster_, request_names_, delta);
        }
      }
    }
    return Http::FilterDataStatus::Continue;
  }

  Http::FilterTrailersStatus encodeTrailers(Http::ResponseTrailerMap& trailers) override {
    if (doStatTracking()) {
      config_->context_.chargeStat(*cluster_, Grpc::Context::Protocol::Grpc, request_names_,
                                   trailers.GrpcStatus());
      maybeChargeUpstreamStat();
    }
    return Http::FilterTrailersStatus::Continue;
  }

  bool doStatTracking() const { return do_stat_tracking_; }

  void maybeWriteFilterState() {
    if (!config_->emit_filter_state_) {
      return;
    }
    if (filter_object_ == nullptr) {
      auto state = std::make_unique<GrpcStatsObject>();
      filter_object_ = state.get();
      decoder_callbacks_->streamInfo().filterState()->setData(
          "envoy.filters.http.grpc_stats", std::move(state),
          StreamInfo::FilterState::StateType::Mutable,
          StreamInfo::FilterState::LifeSpan::FilterChain);
    }
    filter_object_->request_message_count = request_counter_.frameCount();
    filter_object_->response_message_count = response_counter_.frameCount();
  }

  void maybeChargeUpstreamStat() {
    if (config_->enable_upstream_stats_ &&
        decoder_callbacks_->streamInfo().lastUpstreamTxByteSent().has_value() &&
        decoder_callbacks_->streamInfo().lastUpstreamRxByteReceived().has_value()) {
      std::chrono::milliseconds chrono_duration =
          std::chrono::duration_cast<std::chrono::milliseconds>(
              decoder_callbacks_->streamInfo().lastUpstreamRxByteReceived().value() -
              decoder_callbacks_->streamInfo().lastUpstreamTxByteSent().value());
      config_->context_.chargeUpstreamStat(*cluster_, request_names_, chrono_duration);
    }
  }

private:
  ConfigConstSharedPtr config_;
  GrpcStatsObject* filter_object_{};
  bool do_stat_tracking_{false};
  bool grpc_request_{false};
  bool grpc_response_{false};
  Grpc::FrameInspector request_counter_;
  Grpc::FrameInspector response_counter_;
  Upstream::ClusterInfoConstSharedPtr cluster_;
  absl::optional<Grpc::Context::RequestStatNames> request_names_;
}; // namespace

} // namespace

Http::FilterFactoryCb GrpcStatsFilterConfigFactory::createFilterFactoryFromProtoTyped(
    const envoy::extensions::filters::http::grpc_stats::v3::FilterConfig& proto_config,
    const std::string&, Server::Configuration::FactoryContext& factory_context) {

  ConfigConstSharedPtr config = std::make_shared<const Config>(proto_config, factory_context);

  return [config](Http::FilterChainFactoryCallbacks& callbacks) {
    callbacks.addStreamFilter(std::make_shared<GrpcStatsFilter>(config));
  };
}

/**
 * Static registration for the gRPC stats filter. @see RegisterFactory.
 */
REGISTER_FACTORY(GrpcStatsFilterConfigFactory, Server::Configuration::NamedHttpFilterConfigFactory);

} // namespace GrpcStats
} // namespace HttpFilters
} // namespace Extensions
} // namespace Envoy
<commit_msg>Fix wrong comment for closing brace (#18170)<commit_after>#include "source/extensions/filters/http/grpc_stats/grpc_stats_filter.h"

#include "envoy/extensions/filters/http/grpc_stats/v3/config.pb.h"
#include "envoy/extensions/filters/http/grpc_stats/v3/config.pb.validate.h"
#include "envoy/registry/registry.h"

#include "source/common/grpc/codec.h"
#include "source/common/grpc/common.h"
#include "source/common/grpc/context_impl.h"
#include "source/common/runtime/runtime_impl.h"
#include "source/common/stats/symbol_table_impl.h"
#include "source/extensions/filters/http/common/pass_through_filter.h"

namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace GrpcStats {

namespace {

// A map from gRPC service/method name to symbolized stat names for the service/method.
//
// The expected usage pattern is that the map is populated once, and can then be queried lock-free
// as long as it isn't being modified.
class GrpcServiceMethodToRequestNamesMap {
public:
public:
  // Construct a map populated with the services/methods in method_list.
  GrpcServiceMethodToRequestNamesMap(Stats::SymbolTable& symbol_table,
                                     const envoy::config::core::v3::GrpcMethodList& method_list)
      : stat_name_pool_(symbol_table), map_(populate(method_list)) {}

  absl::optional<Grpc::Context::RequestStatNames>
  lookup(const Grpc::Common::RequestNames& request_names) const {
    auto it = map_.find(request_names);
    if (it != map_.end()) {
      return it->second;
    }

    return {};
  }

private:
  using OwningKey = std::tuple<std::string, std::string>;
  using ViewKey = Grpc::Common::RequestNames;

  class MapHash {
  private:
    // Use the same type for hashing all variations to ensure the same hash value from all source
    // types.
    using ViewTuple = std::tuple<absl::string_view, absl::string_view>;
    static uint64_t hash(const ViewTuple& key) { return absl::Hash<ViewTuple>()(key); }

  public:
    using is_transparent = void; // NOLINT(readability-identifier-naming)

    uint64_t operator()(const OwningKey& key) const { return hash(key); }
    uint64_t operator()(const ViewKey& key) const {
      return hash(ViewTuple(key.service_, key.method_));
    }
  };

  struct MapEq {
    using is_transparent = void; // NOLINT(readability-identifier-naming)
    bool operator()(const OwningKey& left, const OwningKey& right) const { return left == right; }
    bool operator()(const OwningKey& left, const ViewKey& right) const {
      return left == std::make_tuple(right.service_, right.method_);
    }
  };
  using MapType = absl::flat_hash_map<OwningKey, Grpc::Context::RequestStatNames, MapHash, MapEq>;

  // Helper for generating a populated MapType so that `map_` can be const.
  MapType populate(const envoy::config::core::v3::GrpcMethodList& method_list) {
    MapType map;
    for (const auto& service : method_list.services()) {
      Stats::StatName stat_name_service = stat_name_pool_.add(service.name());

      for (const auto& method_name : service.method_names()) {
        Stats::StatName stat_name_method = stat_name_pool_.add(method_name);
        map[OwningKey(service.name(), method_name)] =
            Grpc::Context::RequestStatNames{stat_name_service, stat_name_method};
      }
    }
    return map;
  }

  Stats::StatNamePool stat_name_pool_;
  const MapType map_;
};

struct Config {
  Config(const envoy::extensions::filters::http::grpc_stats::v3::FilterConfig& proto_config,
         Server::Configuration::FactoryContext& context)
      : context_(context.grpcContext()), emit_filter_state_(proto_config.emit_filter_state()),
        enable_upstream_stats_(proto_config.enable_upstream_stats()) {

    switch (proto_config.per_method_stat_specifier_case()) {
    case envoy::extensions::filters::http::grpc_stats::v3::FilterConfig::
        PER_METHOD_STAT_SPECIFIER_NOT_SET:
    case envoy::extensions::filters::http::grpc_stats::v3::FilterConfig::kStatsForAllMethods:
      if (proto_config.has_stats_for_all_methods()) {
        stats_for_all_methods_ = proto_config.stats_for_all_methods().value();
      } else {
        // Default for when "grpc_stats_filter_enable_stats_for_all_methods_by_default" isn't
        // set.
        //
        // This will flip to false after one release.
        const bool runtime_feature_default = false;

        const char* runtime_key = "envoy.deprecated_features.grpc_stats_filter_enable_"
                                  "stats_for_all_methods_by_default";

        stats_for_all_methods_ = context.runtime().snapshot().deprecatedFeatureEnabled(
            runtime_key, runtime_feature_default);

        if (stats_for_all_methods_) {
          ENVOY_LOG_MISC(warn,
                         "Using deprecated default value for "
                         "'envoy.extensions.filters.http.grpc_stats.v3.FilterConfig.stats_for_all_"
                         "methods'. The default for this field will become false in a future "
                         "release. To retain this behavior, set this field to true in your "
                         "configuration. A short-term workaround of setting runtime configuration "
                         "{} to true can be used if the configuration cannot be changed.",
                         runtime_key);
        }
      }
      break;

    case envoy::extensions::filters::http::grpc_stats::v3::FilterConfig::
        kIndividualMethodStatsAllowlist:
      allowlist_.emplace(context.scope().symbolTable(),
                         proto_config.individual_method_stats_allowlist());
      break;
    }
  }
  Grpc::Context& context_;
  const bool emit_filter_state_;
  const bool enable_upstream_stats_;
  bool stats_for_all_methods_{false};
  absl::optional<GrpcServiceMethodToRequestNamesMap> allowlist_;
};
using ConfigConstSharedPtr = std::shared_ptr<const Config>;

class GrpcStatsFilter : public Http::PassThroughFilter {
public:
  GrpcStatsFilter(ConfigConstSharedPtr config) : config_(config) {}

  Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers, bool) override {
    grpc_request_ = Grpc::Common::isGrpcRequestHeaders(headers);
    if (grpc_request_) {
      cluster_ = decoder_callbacks_->clusterInfo();
      if (cluster_) {
        if (config_->stats_for_all_methods_) {
          // Get dynamically-allocated Context::RequestStatNames from the context.
          request_names_ = config_->context_.resolveDynamicServiceAndMethod(headers.Path());
          do_stat_tracking_ = request_names_.has_value();
        } else {
          // This case handles both proto_config.stats_for_all_methods() == false,
          // and proto_config.has_individual_method_stats_allowlist(). This works
          // because proto_config.stats_for_all_methods() == false results in
          // an empty allowlist, which exactly matches the behavior specified for
          // this configuration.
          //
          // Resolve the service and method to a string_view, then get
          // the Context::RequestStatNames out of the pre-allocated list that
          // can be produced with the allowlist being present.
          absl::optional<Grpc::Common::RequestNames> request_names =
              Grpc::Common::resolveServiceAndMethod(headers.Path());

          if (request_names) {
            // Do stat tracking as long as this looks like a grpc service/method,
            // even if it isn't in the allowlist. Things not in the allowlist
            // are counted with a stat with no service/method in the name.
            do_stat_tracking_ = true;

            // If the entry is not found in the allowlist, this will return
            // an empty optional; each of the `charge` functions on the context
            // will interpret an empty optional for this value to mean that the
            // service.method prefix on the stat should be omitted.
            if (config_->allowlist_) {
              request_names_ = config_->allowlist_->lookup(*request_names);
            }
          }
        }
      }
    }
    return Http::FilterHeadersStatus::Continue;
  }

  Http::FilterDataStatus decodeData(Buffer::Instance& data, bool) override {
    if (grpc_request_) {
      uint64_t delta = request_counter_.inspect(data);
      if (delta > 0) {
        maybeWriteFilterState();
        if (doStatTracking()) {
          config_->context_.chargeRequestMessageStat(*cluster_, request_names_, delta);
        }
      }
    }
    return Http::FilterDataStatus::Continue;
  }

  Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap& headers,
                                          bool end_stream) override {
    grpc_response_ = Grpc::Common::isGrpcResponseHeaders(headers, end_stream);
    if (doStatTracking()) {
      config_->context_.chargeStat(*cluster_, Grpc::Context::Protocol::Grpc, request_names_,
                                   headers.GrpcStatus());
      if (end_stream) {
        maybeChargeUpstreamStat();
      }
    }
    return Http::FilterHeadersStatus::Continue;
  }

  Http::FilterDataStatus encodeData(Buffer::Instance& data, bool) override {
    if (grpc_response_) {
      uint64_t delta = response_counter_.inspect(data);
      if (delta > 0) {
        maybeWriteFilterState();
        if (doStatTracking()) {
          config_->context_.chargeResponseMessageStat(*cluster_, request_names_, delta);
        }
      }
    }
    return Http::FilterDataStatus::Continue;
  }

  Http::FilterTrailersStatus encodeTrailers(Http::ResponseTrailerMap& trailers) override {
    if (doStatTracking()) {
      config_->context_.chargeStat(*cluster_, Grpc::Context::Protocol::Grpc, request_names_,
                                   trailers.GrpcStatus());
      maybeChargeUpstreamStat();
    }
    return Http::FilterTrailersStatus::Continue;
  }

  bool doStatTracking() const { return do_stat_tracking_; }

  void maybeWriteFilterState() {
    if (!config_->emit_filter_state_) {
      return;
    }
    if (filter_object_ == nullptr) {
      auto state = std::make_unique<GrpcStatsObject>();
      filter_object_ = state.get();
      decoder_callbacks_->streamInfo().filterState()->setData(
          "envoy.filters.http.grpc_stats", std::move(state),
          StreamInfo::FilterState::StateType::Mutable,
          StreamInfo::FilterState::LifeSpan::FilterChain);
    }
    filter_object_->request_message_count = request_counter_.frameCount();
    filter_object_->response_message_count = response_counter_.frameCount();
  }

  void maybeChargeUpstreamStat() {
    if (config_->enable_upstream_stats_ &&
        decoder_callbacks_->streamInfo().lastUpstreamTxByteSent().has_value() &&
        decoder_callbacks_->streamInfo().lastUpstreamRxByteReceived().has_value()) {
      std::chrono::milliseconds chrono_duration =
          std::chrono::duration_cast<std::chrono::milliseconds>(
              decoder_callbacks_->streamInfo().lastUpstreamRxByteReceived().value() -
              decoder_callbacks_->streamInfo().lastUpstreamTxByteSent().value());
      config_->context_.chargeUpstreamStat(*cluster_, request_names_, chrono_duration);
    }
  }

private:
  ConfigConstSharedPtr config_;
  GrpcStatsObject* filter_object_{};
  bool do_stat_tracking_{false};
  bool grpc_request_{false};
  bool grpc_response_{false};
  Grpc::FrameInspector request_counter_;
  Grpc::FrameInspector response_counter_;
  Upstream::ClusterInfoConstSharedPtr cluster_;
  absl::optional<Grpc::Context::RequestStatNames> request_names_;
};

} // namespace

Http::FilterFactoryCb GrpcStatsFilterConfigFactory::createFilterFactoryFromProtoTyped(
    const envoy::extensions::filters::http::grpc_stats::v3::FilterConfig& proto_config,
    const std::string&, Server::Configuration::FactoryContext& factory_context) {

  ConfigConstSharedPtr config = std::make_shared<const Config>(proto_config, factory_context);

  return [config](Http::FilterChainFactoryCallbacks& callbacks) {
    callbacks.addStreamFilter(std::make_shared<GrpcStatsFilter>(config));
  };
}

/**
 * Static registration for the gRPC stats filter. @see RegisterFactory.
 */
REGISTER_FACTORY(GrpcStatsFilterConfigFactory, Server::Configuration::NamedHttpFilterConfigFactory);

} // namespace GrpcStats
} // namespace HttpFilters
} // namespace Extensions
} // namespace Envoy
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
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 author 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.

*/

#include <libtorrent/enum_net.hpp>
#include <libtorrent/socket.hpp>
#include <libtorrent/broadcast_socket.hpp>
#include <vector>
#include <iomanip>
#include <iostream>

using namespace libtorrent;

int main()
{
	io_service ios;
	error_code ec;

	address local = guess_local_address(ios);
	std::cout << "Local address: " << local << std::endl;

	address def_gw = get_default_gateway(ios, ec);
	if (ec)
	{
		std::cerr << ec.message() << std::endl;
		return 1;
	}
	std::cout << "Default gateway: " << def_gw << std::endl;

	std::cout << "=========== Routes ===========\n";
	std::vector<ip_route> routes = enum_routes(ios, ec);
	if (ec)
	{
		std::cerr << ec.message() << std::endl;
		return 1;
	}

	std::cout << std::setiosflags(std::ios::left)
		<< std::setw(18) << "destination"
		<< std::setw(18) << "netmask"
		<< std::setw(35) << "gateway"
		<< "interface name"
		<< std::endl;

	for (std::vector<ip_route>::const_iterator i = routes.begin()
		, end(routes.end()); i != end; ++i)
	{
		std::cout << std::setiosflags(std::ios::left)
			<< std::setw(18) << i->destination
			<< std::setw(18) << i->netmask
			<< std::setw(35) << i->gateway
			<< i->name
			<< std::endl;
	}

	std::cout << "========= Interfaces =========\n";

	std::vector<ip_interface> const& net = enum_net_interfaces(ios, ec);
	if (ec)
	{
		std::cerr << ec.message() << std::endl;
		return 1;
	}

	std::cout << std::setiosflags(std::ios::left)
		<< std::setw(35) << "address"
		<< std::setw(18) << "netmask"
		<< std::setw(18) << "name"
		<< "flags"
		<< std::endl;

	for (std::vector<ip_interface>::const_iterator i = net.begin()
		, end(net.end()); i != end; ++i)
	{
		std::cout << std::setiosflags(std::ios::left)
			<< std::setw(35) << i->interface_address
			<< std::setw(18) << i->netmask
			<< std::setw(18) << i->name
			<< (is_multicast(i->interface_address)?"multicast ":"")
			<< (is_local(i->interface_address)?"local ":"")
			<< (is_loopback(i->interface_address)?"loopback ":"")

			<< std::endl;
	}

}

<commit_msg>replaced iostream in example<commit_after>/*

Copyright (c) 2008, Arvid Norberg
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 author 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.

*/

#include <stdio.h>
#include <libtorrent/enum_net.hpp>
#include <libtorrent/socket.hpp>
#include <libtorrent/broadcast_socket.hpp>

using namespace libtorrent;

int main()
{
	io_service ios;
	error_code ec;
	address local = guess_local_address(ios);
	printf("Local address: %s\n", local.to_string(ec).c_str());

	address def_gw = get_default_gateway(ios, ec);
	if (ec)
	{
		fprintf(stderr, "%s\n", ec.message().c_str());
		return 1;
	}

	printf("Default gateway: %s\n", def_gw.to_string(ec).c_str());

	printf("=========== Routes ===========\n");
	std::vector<ip_route> routes = enum_routes(ios, ec);
	if (ec)
	{
		printf("%s\n", ec.message().c_str());
		return 1;
	}

	printf("%-18s%-18s%-35sinterface name\n", "destination", "network", "gateway");

	for (std::vector<ip_route>::const_iterator i = routes.begin()
		, end(routes.end()); i != end; ++i)
	{
		printf("%-18s%-18s%-35s%s\n"
			, i->destination.to_string(ec).c_str()
			, i->netmask.to_string(ec).c_str()
			, i->gateway.to_string(ec).c_str()
			, i->name);
	}

	printf("========= Interfaces =========\n");

	std::vector<ip_interface> const& net = enum_net_interfaces(ios, ec);
	if (ec)
	{
		printf("%s\n", ec.message().c_str());
		return 1;
	}

	printf("%-18s%-18s%-35sflags\n", "address", "netmask", "name");

	for (std::vector<ip_interface>::const_iterator i = net.begin()
		, end(net.end()); i != end; ++i)
	{
		printf("%-18s%-18s%-35s%s%s%s\n"
			, i->interface_address.to_string(ec).c_str()
			, i->netmask.to_string(ec).c_str()
			, i->name
			, (is_multicast(i->interface_address)?"multicast ":"")
			, (is_local(i->interface_address)?"local ":"")
			, (is_loopback(i->interface_address)?"loopback ":"")
			);
	}
}

<|endoftext|>