<commit_before>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * 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 "exception.h"

#include <cxxabi.h>    // for abi::__cxa_demangle
#include <execinfo.h>  // for backtrace, backtrace_symbols
#include <stdarg.h>    // for va_end, va_list, va_start
#include <stdio.h>     // for vsnprintf

#define BUFFER_SIZE 1024

std::string traceback(const char *filename, int line) {
	std::string t;
#ifdef NDEBUG
       (void)filename;
       (void)line;
#else
	void* callstack[128];

	// retrieve current stack addresses
	int frames = backtrace(callstack, sizeof(callstack) / sizeof(void*));

	t = "\n== Traceback at (" + std::string(filename) + ":" + std::to_string(line) + "):";

	if (frames == 0) {
		t += "\n    <empty, possibly corrupt>";
		return t.c_str();
	}

	// resolve addresses into strings containing "filename(function+address)"
	char** strs = backtrace_symbols(callstack, frames);

	// iterate over the returned symbol lines. skip the first, it is the
	// address of this function.
	for (int i = 0; i < frames; ++i) {
		int status = 0;
		const char *sep = "\t ()+";
		char *mangled, *lasts;
		std::string result;
		for (mangled = strtok_r(strs[i], sep, &lasts); mangled; mangled = strtok_r(nullptr, sep, &lasts)) {
			char* unmangled = abi::__cxa_demangle(mangled, nullptr, 0, &status);
			if (!result.empty()) {
				result += " ";
			}
			if (status == 0) {
				result += unmangled;
			} else {
				result += mangled;
			}
			free(unmangled);
		}
		t += "\n    " + result;
	}

	free(strs);
#endif
	return t;
}

BaseException::BaseException(const char *filename, int line, const char* type, const char *format, ...)
{
	char buffer[BUFFER_SIZE];

	va_list argptr;
	va_start(argptr, format);
	vsnprintf(buffer, BUFFER_SIZE, format, argptr);
	va_end(argptr);
	message.assign(buffer);
	if (message.empty()) {
		message.assign(type);
	}

#ifdef TRACEBACK
	snprintf(buffer, BUFFER_SIZE, "%s:%d", filename, line);
	context.assign(std::string(buffer) + ": " + message);

	traceback = ::traceback(filename, line);
#else
	traceback = "\n== Exception at (" + std::string(filename) + ":" + std::to_string(line) + ")";

	(void)filename;
	(void)line;
	context = message;
#endif
}
<commit_msg>Add traceback to exception if in Debug mode<commit_after>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * 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 "exception.h"

#include <cxxabi.h>    // for abi::__cxa_demangle
#include <execinfo.h>  // for backtrace, backtrace_symbols
#include <stdarg.h>    // for va_end, va_list, va_start
#include <stdio.h>     // for vsnprintf

#define BUFFER_SIZE 1024

std::string traceback(const char *filename, int line) {
	std::string t;
#ifdef NDEBUG
       (void)filename;
       (void)line;
#else
	void* callstack[128];

	// retrieve current stack addresses
	int frames = backtrace(callstack, sizeof(callstack) / sizeof(void*));

	t = "\n== Traceback at (" + std::string(filename) + ":" + std::to_string(line) + "):";

	if (frames == 0) {
		t += "\n    <empty, possibly corrupt>";
		return t.c_str();
	}

	// resolve addresses into strings containing "filename(function+address)"
	char** strs = backtrace_symbols(callstack, frames);

	// iterate over the returned symbol lines. skip the first, it is the
	// address of this function.
	for (int i = 0; i < frames; ++i) {
		int status = 0;
		const char *sep = "\t ()+";
		char *mangled, *lasts;
		std::string result;
		for (mangled = strtok_r(strs[i], sep, &lasts); mangled; mangled = strtok_r(nullptr, sep, &lasts)) {
			char* unmangled = abi::__cxa_demangle(mangled, nullptr, 0, &status);
			if (!result.empty()) {
				result += " ";
			}
			if (status == 0) {
				result += unmangled;
			} else {
				result += mangled;
			}
			free(unmangled);
		}
		t += "\n    " + result;
	}

	free(strs);
#endif
	return t;
}

BaseException::BaseException(const char *filename, int line, const char* type, const char *format, ...)
{
	char buffer[BUFFER_SIZE];

	va_list argptr;
	va_start(argptr, format);
	vsnprintf(buffer, BUFFER_SIZE, format, argptr);
	va_end(argptr);
	message.assign(buffer);
	if (message.empty()) {
		message.assign(type);
	}

#ifndef NDEBUG
	snprintf(buffer, BUFFER_SIZE, "%s:%d", filename, line);
	context.assign(std::string(buffer) + ": " + message);

	traceback = ::traceback(filename, line);
#else
	traceback = "\n== Exception at (" + std::string(filename) + ":" + std::to_string(line) + ")";

	(void)filename;
	(void)line;
	context = message;
#endif
}
<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's 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.
//
//   * The name of the copyright holders may not 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 Intel Corporation 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.
//
//M*/

#include "precomp.hpp"
#include <stdio.h>

/*
   This is a translation to C++ from the Matlab's LMSolve package by Miroslav Balda.
   Here is the original copyright:
   ============================================================================

   Copyright (c) 2007, Miroslav Balda
   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 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.
*/

namespace cv
{

class LMSolverImpl CV_FINAL : public LMSolver
{
public:
    LMSolverImpl() : maxIters(100) { init(); }
    LMSolverImpl(const Ptr<LMSolver::Callback>& _cb, int _maxIters) : cb(_cb), epsx(FLT_EPSILON), epsf(FLT_EPSILON), maxIters(_maxIters) { init(); }
    LMSolverImpl(const Ptr<LMSolver::Callback>& _cb, int _maxIters, double _eps) : cb(_cb), epsx(_eps), epsf(_eps), maxIters(_maxIters) { init(); }

    void init()
    {
        printInterval = 0;
    }

    int run(InputOutputArray _param0) const CV_OVERRIDE
    {
        Mat param0 = _param0.getMat(), x, xd, r, rd, J, A, Ap, v, temp_d, d;
        int ptype = param0.type();

        CV_Assert( (param0.cols == 1 || param0.rows == 1) && (ptype == CV_32F || ptype == CV_64F));
        CV_Assert( cb );

        int lx = param0.rows + param0.cols - 1;
        param0.convertTo(x, CV_64F);

        if( x.cols != 1 )
            transpose(x, x);

        if( !cb->compute(x, r, J) )
            return -1;
        double S = norm(r, NORM_L2SQR);
        int nfJ = 2;

        mulTransposed(J, A, true);
        gemm(J, r, 1, noArray(), 0, v, GEMM_1_T);

        Mat D = A.diag().clone();

        const double Rlo = 0.25, Rhi = 0.75;
        double lambda = 1, lc = 0.75;
        int i, iter = 0;

        if( printInterval != 0 )
        {
            printf("************************************************************************************\n");
            printf("\titr\tnfJ\t\tSUM(r^2)\t\tx\t\tdx\t\tl\t\tlc\n");
            printf("************************************************************************************\n");
        }

        for( ;; )
        {
            CV_Assert( A.type() == CV_64F && A.rows == lx );
            A.copyTo(Ap);
            for( i = 0; i < lx; i++ )
                Ap.at<double>(i, i) += lambda*D.at<double>(i);
            solve(Ap, v, d, DECOMP_EIG);
            subtract(x, d, xd);
            if( !cb->compute(xd, rd, noArray()) )
                return -1;
            nfJ++;
            double Sd = norm(rd, NORM_L2SQR);
            gemm(A, d, -1, v, 2, temp_d);
            double dS = d.dot(temp_d);
            double R = (S - Sd)/(fabs(dS) > DBL_EPSILON ? dS : 1);

            if( R > Rhi )
            {
                lambda *= 0.5;
                if( lambda < lc )
                    lambda = 0;
            }
            else if( R < Rlo )
            {
                // find new nu if R too low
                double t = d.dot(v);
                double nu = (Sd - S)/(fabs(t) > DBL_EPSILON ? t : 1) + 2;
                nu = std::min(std::max(nu, 2.), 10.);
                if( lambda == 0 )
                {
                    invert(A, Ap, DECOMP_EIG);
                    double maxval = DBL_EPSILON;
                    for( i = 0; i < lx; i++ )
                        maxval = std::max(maxval, std::abs(Ap.at<double>(i,i)));
                    lambda = lc = 1./maxval;
                    nu *= 0.5;
                }
                lambda *= nu;
            }

            if( Sd < S )
            {
                nfJ++;
                S = Sd;
                std::swap(x, xd);
                if( !cb->compute(x, r, J) )
                    return -1;
                mulTransposed(J, A, true);
                gemm(J, r, 1, noArray(), 0, v, GEMM_1_T);
            }

            iter++;
            bool proceed = iter < maxIters && norm(d, NORM_INF) >= epsx && norm(r, NORM_INF) >= epsf;

            if( printInterval != 0 && (iter % printInterval == 0 || iter == 1 || !proceed) )
            {
                printf("%c%10d %10d %15.4e %16.4e %17.4e %16.4e %17.4e\n",
                       (proceed ? ' ' : '*'), iter, nfJ, S, x.at<double>(0), d.at<double>(0), lambda, lc);
            }

            if(!proceed)
                break;
        }

        if( param0.size != x.size )
            transpose(x, x);

        x.convertTo(param0, ptype);
        if( iter == maxIters )
            iter = -iter;

        return iter;
    }

    void setCallback(const Ptr<LMSolver::Callback>& _cb) CV_OVERRIDE { cb = _cb; }

    Ptr<LMSolver::Callback> cb;

    double epsx;
    double epsf;
    int maxIters;
    int printInterval;
};

Ptr<LMSolver> createLMSolver(const Ptr<LMSolver::Callback>& cb, int maxIters)
{
    return makePtr<LMSolverImpl>(cb, maxIters);
}

Ptr<LMSolver> createLMSolver(const Ptr<LMSolver::Callback>& cb, int maxIters, double eps)
{
    return makePtr<LMSolverImpl>(cb, maxIters, eps);
}

}
<commit_msg>calib3d: fix uninitialized fields in ctors<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's 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.
//
//   * The name of the copyright holders may not 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 Intel Corporation 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.
//
//M*/

#include "precomp.hpp"
#include <stdio.h>

/*
   This is a translation to C++ from the Matlab's LMSolve package by Miroslav Balda.
   Here is the original copyright:
   ============================================================================

   Copyright (c) 2007, Miroslav Balda
   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 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.
*/

namespace cv
{

class LMSolverImpl CV_FINAL : public LMSolver
{
public:
    LMSolverImpl(const Ptr<LMSolver::Callback>& _cb, int _maxIters, double _eps = FLT_EPSILON)
        : cb(_cb), epsx(_eps), epsf(_eps), maxIters(_maxIters)
    {
        printInterval = 0;
    }

    int run(InputOutputArray _param0) const CV_OVERRIDE
    {
        Mat param0 = _param0.getMat(), x, xd, r, rd, J, A, Ap, v, temp_d, d;
        int ptype = param0.type();

        CV_Assert( (param0.cols == 1 || param0.rows == 1) && (ptype == CV_32F || ptype == CV_64F));
        CV_Assert( cb );

        int lx = param0.rows + param0.cols - 1;
        param0.convertTo(x, CV_64F);

        if( x.cols != 1 )
            transpose(x, x);

        if( !cb->compute(x, r, J) )
            return -1;
        double S = norm(r, NORM_L2SQR);
        int nfJ = 2;

        mulTransposed(J, A, true);
        gemm(J, r, 1, noArray(), 0, v, GEMM_1_T);

        Mat D = A.diag().clone();

        const double Rlo = 0.25, Rhi = 0.75;
        double lambda = 1, lc = 0.75;
        int i, iter = 0;

        if( printInterval != 0 )
        {
            printf("************************************************************************************\n");
            printf("\titr\tnfJ\t\tSUM(r^2)\t\tx\t\tdx\t\tl\t\tlc\n");
            printf("************************************************************************************\n");
        }

        for( ;; )
        {
            CV_Assert( A.type() == CV_64F && A.rows == lx );
            A.copyTo(Ap);
            for( i = 0; i < lx; i++ )
                Ap.at<double>(i, i) += lambda*D.at<double>(i);
            solve(Ap, v, d, DECOMP_EIG);
            subtract(x, d, xd);
            if( !cb->compute(xd, rd, noArray()) )
                return -1;
            nfJ++;
            double Sd = norm(rd, NORM_L2SQR);
            gemm(A, d, -1, v, 2, temp_d);
            double dS = d.dot(temp_d);
            double R = (S - Sd)/(fabs(dS) > DBL_EPSILON ? dS : 1);

            if( R > Rhi )
            {
                lambda *= 0.5;
                if( lambda < lc )
                    lambda = 0;
            }
            else if( R < Rlo )
            {
                // find new nu if R too low
                double t = d.dot(v);
                double nu = (Sd - S)/(fabs(t) > DBL_EPSILON ? t : 1) + 2;
                nu = std::min(std::max(nu, 2.), 10.);
                if( lambda == 0 )
                {
                    invert(A, Ap, DECOMP_EIG);
                    double maxval = DBL_EPSILON;
                    for( i = 0; i < lx; i++ )
                        maxval = std::max(maxval, std::abs(Ap.at<double>(i,i)));
                    lambda = lc = 1./maxval;
                    nu *= 0.5;
                }
                lambda *= nu;
            }

            if( Sd < S )
            {
                nfJ++;
                S = Sd;
                std::swap(x, xd);
                if( !cb->compute(x, r, J) )
                    return -1;
                mulTransposed(J, A, true);
                gemm(J, r, 1, noArray(), 0, v, GEMM_1_T);
            }

            iter++;
            bool proceed = iter < maxIters && norm(d, NORM_INF) >= epsx && norm(r, NORM_INF) >= epsf;

            if( printInterval != 0 && (iter % printInterval == 0 || iter == 1 || !proceed) )
            {
                printf("%c%10d %10d %15.4e %16.4e %17.4e %16.4e %17.4e\n",
                       (proceed ? ' ' : '*'), iter, nfJ, S, x.at<double>(0), d.at<double>(0), lambda, lc);
            }

            if(!proceed)
                break;
        }

        if( param0.size != x.size )
            transpose(x, x);

        x.convertTo(param0, ptype);
        if( iter == maxIters )
            iter = -iter;

        return iter;
    }

    void setCallback(const Ptr<LMSolver::Callback>& _cb) CV_OVERRIDE { cb = _cb; }

    Ptr<LMSolver::Callback> cb;

    double epsx;
    double epsf;
    int maxIters;
    int printInterval;
};

Ptr<LMSolver> createLMSolver(const Ptr<LMSolver::Callback>& cb, int maxIters)
{
    return makePtr<LMSolverImpl>(cb, maxIters);
}

Ptr<LMSolver> createLMSolver(const Ptr<LMSolver::Callback>& cb, int maxIters, double eps)
{
    return makePtr<LMSolverImpl>(cb, maxIters, eps);
}

}
<|endoftext|>


<commit_before>/*
    OpenDeck MIDI platform firmware
    Copyright (C) 2015-2018 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 "SysExConf.h"
#include "../interface/Interface.h"
#include "../Version.h"

//use enum for analog sysex sections due to 7/14 bit number conversion
typedef enum
{
    analogEnabled_sysExSection,
    analogInverted_sysExSection,
    analogType_sysExSection,
    analogMIDIidLSB_sysExSection,
    analogMIDIidMSB_sysExSection,
    analogLowerCClimitLSB_sysExSection,
    analogLowerCClimitMSB_sysExSection,
    analogUpperCClimitLSB_sysExSection,
    analogUpperCClimitMSB_sysExSection
} analogSysExSection_t;

SysExConfig::SysExConfig()
{

}

bool onCustom(uint8_t value)
{
    bool requestValid = true;

    switch(value)
    {
        case FIRMWARE_VERSION_STRING:
        sysEx.addToResponse(SW_VERSION_MAJOR);
        sysEx.addToResponse(SW_VERSION_MINOR);
        sysEx.addToResponse(SW_VERSION_REVISION);
        break;

        case HARDWARE_VERSION_STRING:
        sysEx.addToResponse(BOARD_ID);
        sysEx.addToResponse(HARDWARE_VERSION_MAJOR);
        sysEx.addToResponse(HARDWARE_VERSION_MINOR);
        sysEx.addToResponse(HARDWARE_VERSION_REVISION);
        break;

        case FIRMWARE_HARDWARE_VERSION_STRING:
        sysEx.addToResponse(SW_VERSION_MAJOR);
        sysEx.addToResponse(SW_VERSION_MINOR);
        sysEx.addToResponse(SW_VERSION_REVISION);
        sysEx.addToResponse(BOARD_ID);
        sysEx.addToResponse(HARDWARE_VERSION_MAJOR);
        sysEx.addToResponse(HARDWARE_VERSION_MINOR);
        sysEx.addToResponse(HARDWARE_VERSION_REVISION);
        break;

        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);
        break;

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

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

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

        default:
        requestValid = false;
        break;
    }

    if (requestValid)
    {
        #ifdef DISPLAY_SUPPORTED
        display.displayMIDIevent(displayEventIn, midiMessageSystemExclusive_display, 0, 0, 0);
        #endif
        return true;
    }

    return false;
}

sysExParameter_t onGet(uint8_t block, uint8_t section, uint16_t index)
{
    sysExParameter_t returnValue = 0;
    encDec_14bit_t encDec_14bit;

    switch(block)
    {
        case DB_BLOCK_LED:
        switch(section)
        {
            case ledColorSection:
            returnValue = leds.getColor(index);
            break;

            case ledBlinkSection:
            returnValue = leds.getBlinkState(index);
            break;

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

        case DB_BLOCK_ANALOG:
        switch(section)
        {
            case analogMIDIidLSB_sysExSection:
            case analogMIDIidMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogMIDIidSection, index);
            encDec_14bit.split14bit();

            if (section == analogMIDIidLSB_sysExSection)
                returnValue = encDec_14bit.low;
            else
                returnValue = encDec_14bit.high;
            break;

            case analogLowerCClimitLSB_sysExSection:
            case analogLowerCClimitMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogCClowerLimitSection, index);
            encDec_14bit.split14bit();

            if (section == analogLowerCClimitLSB_sysExSection)
                returnValue = encDec_14bit.low;
            else
                returnValue = encDec_14bit.high;
            break;

            case analogUpperCClimitLSB_sysExSection:
            case analogUpperCClimitMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogCCupperLimitSection, index);
            encDec_14bit.split14bit();

            if (section == analogUpperCClimitLSB_sysExSection)
                returnValue = encDec_14bit.low;
            else
                returnValue = encDec_14bit.high;
            break;

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

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

    #ifdef DISPLAY_SUPPORTED
    display.displayMIDIevent(displayEventIn, midiMessageSystemExclusive_display, 0, 0, 0);
    #endif

    return returnValue;
}

bool onSet(uint8_t block, uint8_t section, uint16_t index, sysExParameter_t newValue)
{
    bool success = false;
    encDec_14bit_t encDec_14bit;

    switch(block)
    {
        case DB_BLOCK_ANALOG:
        switch(section)
        {
            case analogMIDIidLSB_sysExSection:
            case analogMIDIidMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogMIDIidSection, index);
            encDec_14bit.split14bit();

            if (section == analogMIDIidLSB_sysExSection)
                encDec_14bit.low = newValue;
            else
                encDec_14bit.high = newValue;

            encDec_14bit.mergeTo14bit();
            success = database.update(block, analogMIDIidSection, index, encDec_14bit.value);
            break;

            case analogLowerCClimitLSB_sysExSection:
            case analogLowerCClimitMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogCClowerLimitSection, index);
            encDec_14bit.split14bit();

            if (section == analogLowerCClimitLSB_sysExSection)
                encDec_14bit.low = newValue;
            else
                encDec_14bit.high = newValue;

            encDec_14bit.mergeTo14bit();
            success = database.update(block, analogCClowerLimitSection, index, encDec_14bit.value);
            break;

            case analogUpperCClimitLSB_sysExSection:
            case analogUpperCClimitMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogCCupperLimitSection, index);
            encDec_14bit.split14bit();

            if (section == analogUpperCClimitLSB_sysExSection)
                encDec_14bit.low = newValue;
            else
                encDec_14bit.high = newValue;

            encDec_14bit.mergeTo14bit();
            success = database.update(block, analogCCupperLimitSection, index, encDec_14bit.value);
            break;

            case analogTypeSection:
            analog.debounceReset(index);
            success = database.update(block, section, index, newValue);
            break;

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

        case DB_BLOCK_MIDI:
        if (section == midiFeatureSection)
        {
            switch(index)
            {
                case midiFeatureRunningStatus:
                midi.setRunningStatusState(newValue);
                break;

                case midiFeatureStandardNoteOff:
                newValue ? midi.setNoteOffMode(noteOffType_standardNoteOff) : midi.setNoteOffMode(noteOffType_noteOnZeroVel);
                break;

                case midiFeatureDinEnabled:
                midi.setDINMIDIstate(newValue);
                break;

                default:
                break;
            }
        }

        success = database.update(block, section, index, newValue);
        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))
                {
                    success = false;
                }
                else
                {
                    leds.setBlinkTime(newValue);
                }
                break;

                case ledHwParameterFadeTime:
                if ((newValue < FADE_TIME_MIN) || (newValue > FADE_TIME_MAX))
                {
                    success = false;
                }
                else
                {
                    #ifdef BOARD_OPEN_DECK
                    leds.setFadeTime(newValue);
                    #endif
                }
                break;

                case ledHwParameterStartUpRoutine:
                if (newValue > 1)
                    success = false;
                break;
            }

            //write to db if success is true
            if (success)
                success = 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(board.getRGBID(index), rgb_R), colorOff);
            leds.setColor(board.getRGBaddress(board.getRGBID(index), rgb_G), colorOff);
            leds.setColor(board.getRGBaddress(board.getRGBID(index), rgb_B), colorOff);

            //write rgb enabled bit to three leds
            success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_R), newValue);

            if (success)
            {
                success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_G), newValue);

                if (success)
                {
                    success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_B), newValue);
                }
            }

            if (newValue && success)
            {
                //copy over note activation and local control settings from current led index to all three leds
                success = database.update(block, ledActivationNoteSection, board.getRGBaddress(board.getRGBID(index), rgb_R), database.read(block, ledActivationNoteSection, index));

                if (success)
                {
                    success = database.update(block, ledActivationNoteSection, board.getRGBaddress(board.getRGBID(index), rgb_G), database.read(block, ledActivationNoteSection, index));

                    if (success)
                    {
                        success = database.update(block, ledActivationNoteSection, board.getRGBaddress(board.getRGBID(index), rgb_B), database.read(block, ledActivationNoteSection, index));

                        if (success)
                        {
                            success = database.update(block, ledLocalControlSection, board.getRGBaddress(board.getRGBID(index), rgb_R), database.read(block, ledLocalControlSection, index));

                            if (success)
                            {
                                success = database.update(block, ledLocalControlSection, board.getRGBaddress(board.getRGBID(index), rgb_G), database.read(block, ledLocalControlSection, index));

                                if (success)
                                {
                                    success = database.update(block, ledLocalControlSection, board.getRGBaddress(board.getRGBID(index), rgb_B), database.read(block, ledLocalControlSection, index));
                                }
                            }
                        }
                    }
                }
            }
            break;

            case ledActivationNoteSection:
            case ledLocalControlSection:
            //first, find out if RGB led is enabled for this led index
            if (database.read(block, ledRGBenabledSection, index))
            {
                //rgb led enabled - copy these settings to all three leds
                success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_R), newValue);

                if (success)
                {
                    success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_G), newValue);

                    if (success)
                    {
                        success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_B), newValue);
                    }
                }
            }
            else
            {
                //apply to single led only
                success = database.update(block, section, index, newValue);
            }
            break;

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

        case DB_BLOCK_DISPLAY:
        success = true;
        if ((section == displayHwSection) || ((section == displayFeaturesSection) && (index == displayFeatureEnable) && newValue))
        {
            display.init((displayController_t)database.read(DB_BLOCK_DISPLAY, displayHwSection, displayHwController), (displayResolution_t)database.read(DB_BLOCK_DISPLAY, displayHwSection, displayHwResolution));
            display.displayHome();
        }
        else if ((section == displayFeaturesSection) && (index == displayFeatureMIDIeventRetention))
        {
            display.setRetentionState(newValue);
        }
        else if ((section == displayFeaturesSection) && (index == displayFeatureMIDIeventTime))
        {
            if ((newValue >= MIN_MESSAGE_RETENTION_TIME) && (newValue <= MAX_MESSAGE_RETENTION_TIME))
                display.setRetentionTime(newValue * 1000);
            else
                success = false;
        }

        if (success)
            success = database.update(block, section, index, newValue);
        break;

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

    if (success)
    {
        #ifdef DISPLAY_SUPPORTED
        display.displayMIDIevent(displayEventIn, midiMessageSystemExclusive_display, 0, 0, 0);
        #endif

        return true;
    }

    return false;
}

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

void SysExConfig::init()
{
    createLayout();

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

    addCustomRequest(FIRMWARE_VERSION_STRING);
    addCustomRequest(HARDWARE_VERSION_STRING);
    addCustomRequest(FIRMWARE_HARDWARE_VERSION_STRING);
    addCustomRequest(MAX_COMPONENTS_STRING);
    addCustomRequest(REBOOT_APP_STRING);
    addCustomRequest(REBOOT_BTLDR_STRING);
    addCustomRequest(FACTORY_RESET_STRING);
}

SysExConfig sysEx;
<commit_msg>improvements and fixes to onSet sysex handling<commit_after>/*
    OpenDeck MIDI platform firmware
    Copyright (C) 2015-2018 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 "SysExConf.h"
#include "../interface/Interface.h"
#include "../Version.h"

//use enum for analog sysex sections due to 7/14 bit number conversion
typedef enum
{
    analogEnabled_sysExSection,
    analogInverted_sysExSection,
    analogType_sysExSection,
    analogMIDIidLSB_sysExSection,
    analogMIDIidMSB_sysExSection,
    analogLowerCClimitLSB_sysExSection,
    analogLowerCClimitMSB_sysExSection,
    analogUpperCClimitLSB_sysExSection,
    analogUpperCClimitMSB_sysExSection
} analogSysExSection_t;

SysExConfig::SysExConfig()
{

}

bool onCustom(uint8_t value)
{
    bool requestValid = true;

    switch(value)
    {
        case FIRMWARE_VERSION_STRING:
        sysEx.addToResponse(SW_VERSION_MAJOR);
        sysEx.addToResponse(SW_VERSION_MINOR);
        sysEx.addToResponse(SW_VERSION_REVISION);
        break;

        case HARDWARE_VERSION_STRING:
        sysEx.addToResponse(BOARD_ID);
        sysEx.addToResponse(HARDWARE_VERSION_MAJOR);
        sysEx.addToResponse(HARDWARE_VERSION_MINOR);
        sysEx.addToResponse(HARDWARE_VERSION_REVISION);
        break;

        case FIRMWARE_HARDWARE_VERSION_STRING:
        sysEx.addToResponse(SW_VERSION_MAJOR);
        sysEx.addToResponse(SW_VERSION_MINOR);
        sysEx.addToResponse(SW_VERSION_REVISION);
        sysEx.addToResponse(BOARD_ID);
        sysEx.addToResponse(HARDWARE_VERSION_MAJOR);
        sysEx.addToResponse(HARDWARE_VERSION_MINOR);
        sysEx.addToResponse(HARDWARE_VERSION_REVISION);
        break;

        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);
        break;

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

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

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

        default:
        requestValid = false;
        break;
    }

    if (requestValid)
    {
        #ifdef DISPLAY_SUPPORTED
        display.displayMIDIevent(displayEventIn, midiMessageSystemExclusive_display, 0, 0, 0);
        #endif
        return true;
    }

    return false;
}

sysExParameter_t onGet(uint8_t block, uint8_t section, uint16_t index)
{
    sysExParameter_t returnValue = 0;
    encDec_14bit_t encDec_14bit;

    switch(block)
    {
        case DB_BLOCK_LED:
        switch(section)
        {
            case ledColorSection:
            returnValue = leds.getColor(index);
            break;

            case ledBlinkSection:
            returnValue = leds.getBlinkState(index);
            break;

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

        case DB_BLOCK_ANALOG:
        switch(section)
        {
            case analogMIDIidLSB_sysExSection:
            case analogMIDIidMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogMIDIidSection, index);
            encDec_14bit.split14bit();

            if (section == analogMIDIidLSB_sysExSection)
                returnValue = encDec_14bit.low;
            else
                returnValue = encDec_14bit.high;
            break;

            case analogLowerCClimitLSB_sysExSection:
            case analogLowerCClimitMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogCClowerLimitSection, index);
            encDec_14bit.split14bit();

            if (section == analogLowerCClimitLSB_sysExSection)
                returnValue = encDec_14bit.low;
            else
                returnValue = encDec_14bit.high;
            break;

            case analogUpperCClimitLSB_sysExSection:
            case analogUpperCClimitMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogCCupperLimitSection, index);
            encDec_14bit.split14bit();

            if (section == analogUpperCClimitLSB_sysExSection)
                returnValue = encDec_14bit.low;
            else
                returnValue = encDec_14bit.high;
            break;

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

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

    #ifdef DISPLAY_SUPPORTED
    display.displayMIDIevent(displayEventIn, midiMessageSystemExclusive_display, 0, 0, 0);
    #endif

    return returnValue;
}

bool onSet(uint8_t block, uint8_t section, uint16_t index, sysExParameter_t newValue)
{
    bool success = false;
    bool writeToDb = true;
    encDec_14bit_t encDec_14bit;

    switch(block)
    {
        case DB_BLOCK_ANALOG:
        switch(section)
        {
            case analogMIDIidLSB_sysExSection:
            case analogMIDIidMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogMIDIidSection, index);
            encDec_14bit.split14bit();

            if (section == analogMIDIidLSB_sysExSection)
                encDec_14bit.low = newValue;
            else
                encDec_14bit.high = newValue;

            encDec_14bit.mergeTo14bit();
            success = database.update(block, analogMIDIidSection, index, encDec_14bit.value);
            break;

            case analogLowerCClimitLSB_sysExSection:
            case analogLowerCClimitMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogCClowerLimitSection, index);
            encDec_14bit.split14bit();

            if (section == analogLowerCClimitLSB_sysExSection)
                encDec_14bit.low = newValue;
            else
                encDec_14bit.high = newValue;

            encDec_14bit.mergeTo14bit();
            success = database.update(block, analogCClowerLimitSection, index, encDec_14bit.value);
            break;

            case analogUpperCClimitLSB_sysExSection:
            case analogUpperCClimitMSB_sysExSection:
            encDec_14bit.value = database.read(block, analogCCupperLimitSection, index);
            encDec_14bit.split14bit();

            if (section == analogUpperCClimitLSB_sysExSection)
                encDec_14bit.low = newValue;
            else
                encDec_14bit.high = newValue;

            encDec_14bit.mergeTo14bit();
            success = database.update(block, analogCCupperLimitSection, index, encDec_14bit.value);
            break;

            case analogTypeSection:
            analog.debounceReset(index);
            success = database.update(block, section, index, newValue);
            break;

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

        case DB_BLOCK_MIDI:
        //some custom actions required here
        if (section == midiFeatureSection)
        {
            switch(index)
            {
                case midiFeatureRunningStatus:
                midi.setRunningStatusState(newValue);
                break;

                case midiFeatureStandardNoteOff:
                newValue ? midi.setNoteOffMode(noteOffType_standardNoteOff) : midi.setNoteOffMode(noteOffType_noteOnZeroVel);
                break;

                case midiFeatureDinEnabled:
                midi.setDINMIDIstate(newValue);
                break;

                default:
                break;
            }
        }

        success = database.update(block, section, index, newValue);
        break;

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

            case ledBlinkSection:
            //no writing to database
            leds.setBlinkState(index, newValue);
            success = true;
            writeToDb = false;
            break;

            case ledHardwareParameterSection:
            //this entire section needs specific value check since values differ
            //depending on index
            switch(index)
            {
                case ledHwParameterBlinkTime:
                if ((newValue >= BLINK_TIME_MIN) && (newValue <= BLINK_TIME_MAX))
                {
                    leds.setBlinkTime(newValue);
                    success = true;
                }
                break;

                case ledHwParameterFadeTime:
                if ((newValue >= FADE_TIME_MIN) && (newValue <= FADE_TIME_MAX))
                {
                    #ifdef BOARD_OPEN_DECK
                    leds.setFadeTime(newValue);
                    #endif
                    success = true;
                }
                break;

                case ledHwParameterStartUpRoutine:
                if ((newValue <= 1) && (newValue >= 0))
                    success = true;
                break;
            }

            //write to db if success is true and writing should take place
            if (success && writeToDb)
                success = 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(board.getRGBID(index), rgb_R), colorOff);
            leds.setColor(board.getRGBaddress(board.getRGBID(index), rgb_G), colorOff);
            leds.setColor(board.getRGBaddress(board.getRGBID(index), rgb_B), colorOff);

            //write rgb enabled bit to three leds
            success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_R), newValue);

            if (success)
            {
                success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_G), newValue);

                if (success)
                {
                    success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_B), newValue);
                }
            }

            if (newValue && success)
            {
                //copy over note activation and local control settings from current led index to all three leds
                success = database.update(block, ledActivationNoteSection, board.getRGBaddress(board.getRGBID(index), rgb_R), database.read(block, ledActivationNoteSection, index));

                if (success)
                {
                    success = database.update(block, ledActivationNoteSection, board.getRGBaddress(board.getRGBID(index), rgb_G), database.read(block, ledActivationNoteSection, index));

                    if (success)
                    {
                        success = database.update(block, ledActivationNoteSection, board.getRGBaddress(board.getRGBID(index), rgb_B), database.read(block, ledActivationNoteSection, index));

                        if (success)
                        {
                            success = database.update(block, ledLocalControlSection, board.getRGBaddress(board.getRGBID(index), rgb_R), database.read(block, ledLocalControlSection, index));

                            if (success)
                            {
                                success = database.update(block, ledLocalControlSection, board.getRGBaddress(board.getRGBID(index), rgb_G), database.read(block, ledLocalControlSection, index));

                                if (success)
                                {
                                    success = database.update(block, ledLocalControlSection, board.getRGBaddress(board.getRGBID(index), rgb_B), database.read(block, ledLocalControlSection, index));
                                }
                            }
                        }
                    }
                }
            }
            break;

            case ledActivationNoteSection:
            case ledLocalControlSection:
            //first, find out if RGB led is enabled for this led index
            if (database.read(block, ledRGBenabledSection, index))
            {
                //rgb led enabled - copy these settings to all three leds
                success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_R), newValue);

                if (success)
                {
                    success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_G), newValue);

                    if (success)
                    {
                        success = database.update(block, section, board.getRGBaddress(board.getRGBID(index), rgb_B), newValue);
                    }
                }
            }
            else
            {
                //apply to single led only
                success = database.update(block, section, index, newValue);
            }
            break;

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

        case DB_BLOCK_DISPLAY:
        switch(section)
        {
            case displayHwSection:
            switch(index)
            {
                case displayHwController:
                if ((newValue <= DISPLAY_CONTROLLERS) && (newValue >= 0))
                {
                    display.init((displayController_t)newValue, (displayResolution_t)database.read(DB_BLOCK_DISPLAY, displayHwSection, displayHwResolution));
                    display.displayHome();
                    success = true;
                }
                break;

                case displayHwResolution:
                if ((newValue <= DISPLAY_RESOLUTIONS) && (newValue >= 0))
                {
                    display.init((displayController_t)database.read(DB_BLOCK_DISPLAY, displayHwSection, displayHwController), (displayResolution_t)newValue);
                    display.displayHome();
                    success = true;
                }
                break;

                default:
                break;
            }
            break;

            case displayFeaturesSection:
            switch(index)
            {
                case displayFeatureMIDIeventRetention:
                if ((newValue <= 1) && (newValue >= 0))
                {
                    display.setRetentionState(newValue);
                    success = true;
                }
                break;

                case displayFeatureMIDIeventTime:
                if ((newValue >= MIN_MESSAGE_RETENTION_TIME) && (newValue <= MAX_MESSAGE_RETENTION_TIME))
                {
                    display.setRetentionTime(newValue * 1000);
                    success = true;
                }
                break;

                default:
                break;
            }
            break;

            default:
            break;
        }

        if (success)
            success = database.update(block, section, index, newValue);
        break;

        default:
        //rest of the blocks - no custom handling
        success = database.update(block, section, index, newValue);
        break;
    }

    if (success)
    {
        #ifdef DISPLAY_SUPPORTED
        display.displayMIDIevent(displayEventIn, midiMessageSystemExclusive_display, 0, 0, 0);
        #endif

        return true;
    }

    return false;
}

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

void SysExConfig::init()
{
    createLayout();

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

    addCustomRequest(FIRMWARE_VERSION_STRING);
    addCustomRequest(HARDWARE_VERSION_STRING);
    addCustomRequest(FIRMWARE_HARDWARE_VERSION_STRING);
    addCustomRequest(MAX_COMPONENTS_STRING);
    addCustomRequest(REBOOT_APP_STRING);
    addCustomRequest(REBOOT_BTLDR_STRING);
    addCustomRequest(FACTORY_RESET_STRING);
}

SysExConfig sysEx;
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Magnus Jonsson & 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/file.hpp"
#include <sstream>

#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_LocalFree
	{
	public:
		auto_LocalFree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_LocalFree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	void throw_exception(const char* thrower)
	{
		char *buffer = 0;
		int err = GetLastError();

		#ifdef _UNICODE
			FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM
				|FORMAT_MESSAGE_ALLOCATE_BUFFER
				, 0, err, 0, (LPWSTR)(LPCSTR)&buffer, 0, 0);
		#else
			FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM
				|FORMAT_MESSAGE_ALLOCATE_BUFFER
				, 0, err, 0, (LPSTR)&buffer, 0, 0);
		#endif

		auto_LocalFree auto_free(buffer); // needed for exception safety
		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef _UNICODE
			std::wstring wfile_name(utf8_wchar(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				file_name
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Magnus Jonsson & 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/file.hpp"
#include "libtorrent/utf8.hpp"

#include <sstream>
#include <windows.h>

namespace
{
	// must be used to not leak memory in case something would throw
	class auto_localfree
	{
	public:
		auto_localfree(HLOCAL memory)
			: m_memory(memory)
		{
		}
		~auto_localfree()
		{
			if (m_memory)
				LocalFree(m_memory);
		}
	private:
		HLOCAL m_memory;
	};

	void throw_exception(const char* thrower)
	{
		char *buffer = 0;
		int err = GetLastError();

		#ifdef _UNICODE
			FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM
				|FORMAT_MESSAGE_ALLOCATE_BUFFER
				, 0, err, 0, (LPWSTR)(LPCSTR)&buffer, 0, 0);
		#else
			FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM
				|FORMAT_MESSAGE_ALLOCATE_BUFFER
				, 0, err, 0, (LPSTR)&buffer, 0, 0);
		#endif

		auto_localfree auto_free(buffer); // needed for exception safety
		std::stringstream s;
		s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");

		throw libtorrent::file_error(s.str());
	}
}

namespace libtorrent
{

	struct file::impl : boost::noncopyable
	{
		enum open_flags
		{
			read_flag = 1,
			write_flag = 2
		};

		enum seek_mode
		{
			seek_begin = FILE_BEGIN,
			seek_from_here = FILE_CURRENT,
			seek_end = FILE_END
		};

		impl()
		{
			m_file_handle = INVALID_HANDLE_VALUE;
		}

		void open(const char *file_name, open_flags flags)
		{
			assert(file_name);
			assert(flags & (read_flag | write_flag));

			DWORD access_mask = 0;
			if (flags & read_flag)
				access_mask |= GENERIC_READ;
			if (flags & write_flag)
				access_mask |= GENERIC_WRITE;

			assert(access_mask & (GENERIC_READ | GENERIC_WRITE));

		#ifdef _UNICODE
			std::wstring wfile_name(utf8_wchar(file_name));
			HANDLE new_handle = CreateFile(
				(LPCWSTR)wfile_name.c_str()
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#else
			HANDLE new_handle = CreateFile(
				file_name
				, access_mask
				, FILE_SHARE_READ
				, 0
				, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
				, FILE_ATTRIBUTE_NORMAL
				, 0);
		#endif

			if (new_handle == INVALID_HANDLE_VALUE)
			{
				std::stringstream s;
				throw_exception(file_name);
			}
			// will only close old file if the open succeeded
			close();
			m_file_handle = new_handle;
		}

		void close()
		{
			if (m_file_handle != INVALID_HANDLE_VALUE)
			{
				CloseHandle(m_file_handle);
				m_file_handle = INVALID_HANDLE_VALUE;
			}
		}

		~impl()
		{
			close();
		}

		size_type write(const char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);
			DWORD bytes_written = 0;
			if (num_bytes != 0)
			{
				if (FALSE == WriteFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_written
					, 0))
				{
					throw_exception("file::write");
				}
			}
			return bytes_written;
		}

		size_type read(char* buffer, size_type num_bytes)
		{
			assert(buffer);
			assert(num_bytes > 0);
			assert((DWORD)num_bytes == num_bytes);

			DWORD bytes_read = 0;
			if (num_bytes != 0)
			{
				if (FALSE == ReadFile(
					m_file_handle
					, buffer
					, (DWORD)num_bytes
					, &bytes_read
					, 0))
				{
					throw_exception("file::read");
				}
			}
			return bytes_read;
		}

		void seek(size_type pos, seek_mode from_where)
		{
			assert(pos >= 0 || from_where != seek_begin);
			assert(pos <= 0 || from_where != seek_end);
			LARGE_INTEGER offs;
			offs.QuadPart = pos;
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, from_where))
			{
				throw_exception("file::seek");
			}
		}

		size_type tell()
		{
			LARGE_INTEGER offs;
			offs.QuadPart = 0;

			// is there any other way to get offset?
			if (FALSE == SetFilePointerEx(
				m_file_handle
				, offs
				, &offs
				, FILE_CURRENT))
			{
				throw_exception("file::tell");
			}

			size_type pos=offs.QuadPart;
			assert(pos>=0);
			return pos;
		}
/*
		size_type size()
		{
			LARGE_INTEGER s;
			if (FALSE == GetFileSizeEx(m_file_handle, &s))
			{
				throw_exception("file::size");
			}

			size_type size = s.QuadPart;
			assert(size >= 0);
			return size;
		}
*/
	private:

		HANDLE m_file_handle;

	};
}

namespace libtorrent
{

	const file::seek_mode file::begin(file::impl::seek_begin);
	const file::seek_mode file::end(file::impl::seek_end);

	const file::open_mode file::in(file::impl::read_flag);
	const file::open_mode file::out(file::impl::write_flag);

	file::file()
		: m_impl(new libtorrent::file::impl())
	{
	}
	file::file(boost::filesystem::path const& p, open_mode m)
		: m_impl(new libtorrent::file::impl())
	{
		open(p,m);
	}

	file::~file()
	{
	}

	void file::open(boost::filesystem::path const& p, open_mode m)
	{
		assert(p.is_complete());
		m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buffer, size_type num_bytes)
	{
		return m_impl->write(buffer, num_bytes);
	}

	size_type file::read(char* buffer, size_type num_bytes)
	{
		return m_impl->read(buffer, num_bytes);
	}

	void file::seek(size_type pos, seek_mode m)
	{
		m_impl->seek(pos,impl::seek_mode(m.m_val));
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}
}
<|endoftext|>


<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.
#include "global_timestamp_reader.h"
#include <chrono>

namespace librealsense
{
    CLinearCoefficients::CLinearCoefficients(unsigned int buffer_size) :
        _base_sample(0, 0),
        _buffer_size(buffer_size)
    {
        LOG_DEBUG("CLinearCoefficients started");
    }

    void CLinearCoefficients::reset()
    {
        _last_values.clear();
        LOG_DEBUG("CLinearCoefficients::reset");
    }

    CSample& CSample::operator-=(const CSample& other)
    {
        _x -= other._x;
        _y -= other._y;
        return *this;
    }

    CSample& CSample::operator+=(const CSample& other)
    {
        _x += other._x;
        _y += other._y;
        return *this;
    }

    bool CLinearCoefficients::is_full() const
    {
        return _last_values.size() >= _buffer_size;
    }

    void CLinearCoefficients::add_value(CSample val)
    {
        LOG_DEBUG("CLinearCoefficients::add_value - in");
        std::lock_guard<std::recursive_mutex> lock(_add_mtx);   // Redandent as only being read from update_diff_time() and there is a lock there.
        LOG_DEBUG("CLinearCoefficients::add_value - lock");
        while (_last_values.size() > _buffer_size)
        {
            _last_values.pop_back();
        }
        _last_values.push_front(val);
        calc_linear_coefs();
        LOG_DEBUG("CLinearCoefficients::add_value - unlock");
    }

    void CLinearCoefficients::calc_linear_coefs()
    {
        // Calculate linear coefficients, based on calculus described in: https://www.statisticshowto.datasciencecentral.com/probability-and-statistics/regression-analysis/find-a-linear-regression-equation/
        // Calculate Std
        LOG_DEBUG("CLinearCoefficients::calc_linear_coefs - in");
        double sum_x(0);
        double sum_y(0);
        double sum_xy(0);
        double sum_x2(0);
        double n(static_cast<double>(_last_values.size()));
        CSample base_sample = _last_values.back();
        double a(1);
        double b(0);
        if (n > 1)
        {
            for (auto sample = _last_values.begin(); sample != _last_values.end(); sample++)
            {
                CSample crnt_sample(*sample);
                crnt_sample -= base_sample;
                sum_x += crnt_sample._x;
                sum_y += crnt_sample._y;
                sum_xy += (crnt_sample._x * crnt_sample._y);
                sum_x2 += (crnt_sample._x * crnt_sample._x);
            }
            b = (sum_y*sum_x2 - sum_x * sum_xy) / (n*sum_x2 - sum_x * sum_x);
            a = (n*sum_xy - sum_x * sum_y) / (n*sum_x2 - sum_x * sum_x);
        }
        std::lock_guard<std::recursive_mutex> lock(_stat_mtx);
        LOG_DEBUG("CLinearCoefficients::calc_linear_coefs - lock");
        _base_sample = base_sample;
        _a = a;
        _b = b;
        LOG_DEBUG("CLinearCoefficients::calc_linear_coefs - unlock");
    }

    double CLinearCoefficients::calc_value(double x) const
    {
        LOG_DEBUG("CLinearCoefficients::calc_value - in");
        std::lock_guard<std::recursive_mutex> lock(_stat_mtx);
        LOG_DEBUG("CLinearCoefficients::calc_value - lock");
        double y(_a * (x - _base_sample._x) + _b + _base_sample._y);
        LOG_DEBUG("CLinearCoefficients::calc_value - unlock");
        return y;
    }

    time_diff_keeper::time_diff_keeper(device* dev, const unsigned int sampling_interval_ms) :
        _device(dev),
        _poll_intervals_ms(sampling_interval_ms),
        _last_sample_hw_time(1e+200),
        _coefs(15),
        _users_count(0),
        _active_object([this](dispatcher::cancellable_timer cancellable_timer)
            {
                polling(cancellable_timer);
            })
    {
        LOG_DEBUG("start new time_diff_keeper ");
    }

    void time_diff_keeper::start()
    {
        _users_count++;
        LOG_INFO("start: _users_count = " << _users_count);
        _active_object.start();
    }

    void time_diff_keeper::stop()
    {
        if (_users_count <= 0)
            throw wrong_api_call_sequence_exception(to_string() << "time_diff_keeper users_count <= 0.");

        LOG_INFO("stop: _users_count = " << _users_count);
        _users_count--;
        if (_users_count == 0)
        {
            LOG_INFO("stop: top object.");
            _active_object.stop();
            _coefs.reset();
        }
    }

    time_diff_keeper::~time_diff_keeper()
    {
        _active_object.stop();
    }

    bool time_diff_keeper::update_diff_time()
    {
        using namespace std::chrono;
        try
        {
            LOG_DEBUG("time_diff_keeper::update_diff_time - in");
            std::lock_guard<std::recursive_mutex> lock(_mtx);
            LOG_DEBUG("time_diff_keeper::update_diff_time - lock");
            double system_time_start = duration<double, std::milli>(system_clock::now().time_since_epoch()).count();
            double sample_hw_time = _device->get_device_time();
            double system_time_finish = duration<double, std::milli>(system_clock::now().time_since_epoch()).count();
            double system_time((system_time_finish + system_time_start) / 2);
            if (sample_hw_time < _last_sample_hw_time)
            {
                // A time loop happend:
                LOG_DEBUG("time_diff_keeper::call reset()");
                _coefs.reset();
            }
            _last_sample_hw_time = sample_hw_time;
            CSample crnt_sample(_last_sample_hw_time, system_time);
            _coefs.add_value(crnt_sample);
            LOG_DEBUG("time_diff_keeper::update_diff_time - unlock");
            return true;
        }
        catch (const wrong_api_call_sequence_exception& ex)
        {
            LOG_DEBUG("Temporary skip during time_diff_keeper polling: " << ex.what());
        }
        catch (const std::exception& ex)
        {
            LOG_ERROR("Error during time_diff_keeper polling: " << ex.what());
        }
        catch (...)
        {
            LOG_ERROR("Unknown error during time_diff_keeper polling!");
        }
        return false;
    }

    void time_diff_keeper::polling(dispatcher::cancellable_timer cancellable_timer)
    {
        unsigned int time_to_sleep = _poll_intervals_ms + _coefs.is_full() * (9 * _poll_intervals_ms);
        if (cancellable_timer.try_sleep(time_to_sleep))
        {
            update_diff_time();
        }
        else
        {
            LOG_DEBUG("Notification: time_diff_keeper polling loop is being shut-down");
        }
    }

    double time_diff_keeper::get_system_hw_time(double crnt_hw_time)
    {
        static const double possible_loop_time(3000);
        {
            LOG_DEBUG("time_diff_keeper::get_system_hw_time - in");
            std::lock_guard<std::recursive_mutex> lock(_read_mtx);
            LOG_DEBUG("time_diff_keeper::get_system_hw_time - lock");
            if ((_last_sample_hw_time - crnt_hw_time) > possible_loop_time)
            {
                update_diff_time();
            }
            LOG_DEBUG("time_diff_keeper::get_system_hw_time - unlock");
        }
        return _coefs.calc_value(crnt_hw_time);
    }

    global_timestamp_reader::global_timestamp_reader(std::unique_ptr<frame_timestamp_reader> device_timestamp_reader,
                                                     std::shared_ptr<time_diff_keeper> timediff,
                                                     std::shared_ptr<global_time_option> enable_option) :
        _device_timestamp_reader(std::move(device_timestamp_reader)),
        _time_diff_keeper(timediff),
        _option_is_enabled(enable_option)
    {
        LOG_DEBUG("global_timestamp_reader created");
    }

    double global_timestamp_reader::get_frame_timestamp(const request_mapping& mode, const platform::frame_object& fo)
    {
        double frame_time = _device_timestamp_reader->get_frame_timestamp(mode, fo);
        rs2_timestamp_domain ts_domain = _device_timestamp_reader->get_frame_timestamp_domain(mode, fo);
        if (_option_is_enabled->is_true() && ts_domain == RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK)
        {
            auto sp = _time_diff_keeper.lock();
            if (sp)
                frame_time = sp->get_system_hw_time(frame_time);
            else
                LOG_DEBUG("Notification: global_timestamp_reader - time_diff_keeper is being shut-down");
        }
        return frame_time;
    }

    unsigned long long global_timestamp_reader::get_frame_counter(const request_mapping& mode, const platform::frame_object& fo) const
    {
        return _device_timestamp_reader->get_frame_counter(mode, fo);
    }

    rs2_timestamp_domain global_timestamp_reader::get_frame_timestamp_domain(const request_mapping& mode, const platform::frame_object& fo) const
    {
        rs2_timestamp_domain ts_domain = _device_timestamp_reader->get_frame_timestamp_domain(mode, fo);
        return (_option_is_enabled->is_true() && ts_domain == RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK) ? RS2_TIMESTAMP_DOMAIN_GLOBAL_TIME : ts_domain;
    }

    void global_timestamp_reader::reset()
    {
        _device_timestamp_reader->reset();
    }
}
<commit_msg>change logs<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.
#include "global_timestamp_reader.h"
#include <chrono>

namespace librealsense
{
    CLinearCoefficients::CLinearCoefficients(unsigned int buffer_size) :
        _base_sample(0, 0),
        _buffer_size(buffer_size)
    {
        LOG_DEBUG("CLinearCoefficients started");
    }

    void CLinearCoefficients::reset()
    {
        _last_values.clear();
        LOG_DEBUG("CLinearCoefficients::reset");
    }

    CSample& CSample::operator-=(const CSample& other)
    {
        _x -= other._x;
        _y -= other._y;
        return *this;
    }

    CSample& CSample::operator+=(const CSample& other)
    {
        _x += other._x;
        _y += other._y;
        return *this;
    }

    bool CLinearCoefficients::is_full() const
    {
        return _last_values.size() >= _buffer_size;
    }

    void CLinearCoefficients::add_value(CSample val)
    {
        LOG_DEBUG("CLinearCoefficients::add_value - in");
        std::lock_guard<std::recursive_mutex> lock(_add_mtx);   // Redandent as only being read from update_diff_time() and there is a lock there.
        LOG_DEBUG("CLinearCoefficients::add_value - lock");
        while (_last_values.size() > _buffer_size)
        {
            _last_values.pop_back();
        }
        _last_values.push_front(val);
        calc_linear_coefs();
        LOG_DEBUG("CLinearCoefficients::add_value - unlock");
    }

    void CLinearCoefficients::calc_linear_coefs()
    {
        // Calculate linear coefficients, based on calculus described in: https://www.statisticshowto.datasciencecentral.com/probability-and-statistics/regression-analysis/find-a-linear-regression-equation/
        // Calculate Std
        LOG_DEBUG("CLinearCoefficients::calc_linear_coefs - in");
        double sum_x(0);
        double sum_y(0);
        double sum_xy(0);
        double sum_x2(0);
        double n(static_cast<double>(_last_values.size()));
        CSample base_sample = _last_values.back();
        double a(1);
        double b(0);
        if (n > 1)
        {
            for (auto sample = _last_values.begin(); sample != _last_values.end(); sample++)
            {
                CSample crnt_sample(*sample);
                crnt_sample -= base_sample;
                sum_x += crnt_sample._x;
                sum_y += crnt_sample._y;
                sum_xy += (crnt_sample._x * crnt_sample._y);
                sum_x2 += (crnt_sample._x * crnt_sample._x);
            }
            b = (sum_y*sum_x2 - sum_x * sum_xy) / (n*sum_x2 - sum_x * sum_x);
            a = (n*sum_xy - sum_x * sum_y) / (n*sum_x2 - sum_x * sum_x);
        }
        std::lock_guard<std::recursive_mutex> lock(_stat_mtx);
        LOG_DEBUG("CLinearCoefficients::calc_linear_coefs - lock");
        _base_sample = base_sample;
        _a = a;
        _b = b;
        LOG_DEBUG("CLinearCoefficients::calc_linear_coefs - unlock");
    }

    double CLinearCoefficients::calc_value(double x) const
    {
        LOG_DEBUG("CLinearCoefficients::calc_value - in");
        std::lock_guard<std::recursive_mutex> lock(_stat_mtx);
        LOG_DEBUG("CLinearCoefficients::calc_value - lock");
        double y(_a * (x - _base_sample._x) + _b + _base_sample._y);
        LOG_DEBUG("CLinearCoefficients::calc_value - unlock");
        return y;
    }

    time_diff_keeper::time_diff_keeper(device* dev, const unsigned int sampling_interval_ms) :
        _device(dev),
        _poll_intervals_ms(sampling_interval_ms),
        _last_sample_hw_time(1e+200),
        _coefs(15),
        _users_count(0),
        _active_object([this](dispatcher::cancellable_timer cancellable_timer)
            {
                polling(cancellable_timer);
            })
    {
        LOG_DEBUG("start new time_diff_keeper ");
    }

    void time_diff_keeper::start()
    {
        _users_count++;
        LOG_DEBUG("start: _users_count = " << _users_count);
        _active_object.start();
    }

    void time_diff_keeper::stop()
    {
        if (_users_count <= 0)
            throw wrong_api_call_sequence_exception(to_string() << "time_diff_keeper users_count <= 0.");

        _users_count--;
        LOG_DEBUG("stop: _users_count = " << _users_count);
        if (_users_count == 0)
        {
            LOG_DEBUG("stop: stop object.");
            _active_object.stop();
            _coefs.reset();
        }
    }

    time_diff_keeper::~time_diff_keeper()
    {
        _active_object.stop();
    }

    bool time_diff_keeper::update_diff_time()
    {
        using namespace std::chrono;
        try
        {
            LOG_DEBUG("time_diff_keeper::update_diff_time - in");
            std::lock_guard<std::recursive_mutex> lock(_mtx);
            LOG_DEBUG("time_diff_keeper::update_diff_time - lock");
            double system_time_start = duration<double, std::milli>(system_clock::now().time_since_epoch()).count();
            double sample_hw_time = _device->get_device_time();
            double system_time_finish = duration<double, std::milli>(system_clock::now().time_since_epoch()).count();
            double system_time((system_time_finish + system_time_start) / 2);
            if (sample_hw_time < _last_sample_hw_time)
            {
                // A time loop happend:
                LOG_DEBUG("time_diff_keeper::call reset()");
                _coefs.reset();
            }
            _last_sample_hw_time = sample_hw_time;
            CSample crnt_sample(_last_sample_hw_time, system_time);
            _coefs.add_value(crnt_sample);
            LOG_DEBUG("time_diff_keeper::update_diff_time - unlock");
            return true;
        }
        catch (const wrong_api_call_sequence_exception& ex)
        {
            LOG_DEBUG("Temporary skip during time_diff_keeper polling: " << ex.what());
        }
        catch (const std::exception& ex)
        {
            LOG_ERROR("Error during time_diff_keeper polling: " << ex.what());
        }
        catch (...)
        {
            LOG_ERROR("Unknown error during time_diff_keeper polling!");
        }
        return false;
    }

    void time_diff_keeper::polling(dispatcher::cancellable_timer cancellable_timer)
    {
        unsigned int time_to_sleep = _poll_intervals_ms + _coefs.is_full() * (9 * _poll_intervals_ms);
        if (cancellable_timer.try_sleep(time_to_sleep))
        {
            update_diff_time();
        }
        else
        {
            LOG_DEBUG("Notification: time_diff_keeper polling loop is being shut-down");
        }
    }

    double time_diff_keeper::get_system_hw_time(double crnt_hw_time)
    {
        static const double possible_loop_time(3000);
        {
            LOG_DEBUG("time_diff_keeper::get_system_hw_time - in");
            std::lock_guard<std::recursive_mutex> lock(_read_mtx);
            LOG_DEBUG("time_diff_keeper::get_system_hw_time - lock");
            if ((_last_sample_hw_time - crnt_hw_time) > possible_loop_time)
            {
                update_diff_time();
            }
            LOG_DEBUG("time_diff_keeper::get_system_hw_time - unlock");
        }
        return _coefs.calc_value(crnt_hw_time);
    }

    global_timestamp_reader::global_timestamp_reader(std::unique_ptr<frame_timestamp_reader> device_timestamp_reader,
                                                     std::shared_ptr<time_diff_keeper> timediff,
                                                     std::shared_ptr<global_time_option> enable_option) :
        _device_timestamp_reader(std::move(device_timestamp_reader)),
        _time_diff_keeper(timediff),
        _option_is_enabled(enable_option)
    {
        LOG_DEBUG("global_timestamp_reader created");
    }

    double global_timestamp_reader::get_frame_timestamp(const request_mapping& mode, const platform::frame_object& fo)
    {
        double frame_time = _device_timestamp_reader->get_frame_timestamp(mode, fo);
        rs2_timestamp_domain ts_domain = _device_timestamp_reader->get_frame_timestamp_domain(mode, fo);
        if (_option_is_enabled->is_true() && ts_domain == RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK)
        {
            auto sp = _time_diff_keeper.lock();
            if (sp)
                frame_time = sp->get_system_hw_time(frame_time);
            else
                LOG_DEBUG("Notification: global_timestamp_reader - time_diff_keeper is being shut-down");
        }
        return frame_time;
    }

    unsigned long long global_timestamp_reader::get_frame_counter(const request_mapping& mode, const platform::frame_object& fo) const
    {
        return _device_timestamp_reader->get_frame_counter(mode, fo);
    }

    rs2_timestamp_domain global_timestamp_reader::get_frame_timestamp_domain(const request_mapping& mode, const platform::frame_object& fo) const
    {
        rs2_timestamp_domain ts_domain = _device_timestamp_reader->get_frame_timestamp_domain(mode, fo);
        return (_option_is_enabled->is_true() && ts_domain == RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK) ? RS2_TIMESTAMP_DOMAIN_GLOBAL_TIME : ts_domain;
    }

    void global_timestamp_reader::reset()
    {
        _device_timestamp_reader->reset();
    }
}
<|endoftext|>