<commit_before>/*
   Copyright (C) 2015 Preet Desai (preet.desai@gmail.com)

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include <ks/KsLog.hpp>

#ifdef KS_ENV_ANDROID
#include <android/log.hpp>
#endif

namespace ks
{
    namespace Log
    {
        #ifdef KS_ENV_ANDROID
            void SinkToLogCat::log(std::string const &line)
            {
                m_mutex.lock();
                __android_log_print(ANDROID_LOG_VERBOSE,"ks",line.c_str());
                m_mutex.unlock();
            }
        #endif

        // ============================================================= //

        FBRunTimeMs::FBRunTimeMs() :
            m_time_str("00:00:00.000"),
            m_start(std::chrono::system_clock::now()),
            m_list_num_chars({{'0','1','2','3','4','5','6','7','8','9'}})
        {
            // empty
        }

        FBRunTimeMs::~FBRunTimeMs()
        {
            // empty
        }

        std::string FBRunTimeMs::Get()
        {
            // TODO: should we use steady_clock, not system clock?
            auto now = std::chrono::system_clock::now();
            std::chrono::system_clock::duration elapsed = now-m_start;

            std::chrono::hours hours =
                    std::chrono::duration_cast<std::chrono::hours>(
                        elapsed);
            elapsed -= hours;

            std::chrono::minutes mins =
                    std::chrono::duration_cast<std::chrono::minutes>(
                        elapsed);
            elapsed -= mins;

            std::chrono::seconds secs =
                    std::chrono::duration_cast<std::chrono::seconds>(
                        elapsed);
            elapsed -= secs;

            std::chrono::milliseconds ms =
                    std::chrono::duration_cast<std::chrono::milliseconds>(
                        elapsed);

            uint_fast8_t const hours_count = hours.count();
            uint_fast8_t const mins_count = mins.count();
            uint_fast8_t const secs_count = secs.count();
            uint_fast16_t const ms_count = ms.count();

            m_time_str[0] = m_list_num_chars[hours_count/10];
            m_time_str[1] = m_list_num_chars[hours_count%10];

            m_time_str[3] = m_list_num_chars[mins_count/10];
            m_time_str[4] = m_list_num_chars[mins_count%10];

            m_time_str[6] = m_list_num_chars[secs_count/10];
            m_time_str[7] = m_list_num_chars[secs_count%10];

            m_time_str[9] = m_list_num_chars[ms_count/100];
            m_time_str[10] = m_list_num_chars[(ms_count%100)/10];
            m_time_str[11] = m_list_num_chars[(ms_count%100)%10];

            return m_time_str;
        }

        FBCustomStr::FBCustomStr(std::string const &s) : m_s(s)
        {
            // empty
        }

        FBCustomStr::~FBCustomStr()
        {
            // empty
        }

        std::string FBCustomStr::Get()
        {
            return m_s;
        }

        // ============================================================= //

        Logger::Logger()
        {
            m_mutex = make_unique<MutexSTL>();

            // default filter is all on
            m_filter.set(static_cast<size_t>(Level::TRACE));
            m_filter.set(static_cast<size_t>(Level::DEBUG));
            m_filter.set(static_cast<size_t>(Level::INFO));
            m_filter.set(static_cast<size_t>(Level::WARN));
            m_filter.set(static_cast<size_t>(Level::ERROR));
            m_filter.set(static_cast<size_t>(Level::FATAL));
        }

        Logger::Logger(bool thread_safe,
                       shared_ptr<Sink> const &sink,
                       std::array<std::vector<FormatBlock*>,6> && list_fbs)
        {
            if(thread_safe) {
                m_mutex = make_unique<MutexSTL>();
            }
            else {
                m_mutex = make_unique<MutexDummy>();
            }

            // save sink
            m_list_sinks.push_back(sink);

            // save format blocks
            for(uint level=0; level < 6; level++) {
                for(uint fb_idx=0; fb_idx < list_fbs[level].size(); fb_idx++) {
                    m_list_fb[level].push_back(
                                std::move(unique_ptr<FormatBlock>(
                                              list_fbs[level][fb_idx])));
                }
            }

            // default filter is all on
            m_filter.set(static_cast<size_t>(Level::TRACE));
            m_filter.set(static_cast<size_t>(Level::DEBUG));
            m_filter.set(static_cast<size_t>(Level::INFO));
            m_filter.set(static_cast<size_t>(Level::WARN));
            m_filter.set(static_cast<size_t>(Level::ERROR));
            m_filter.set(static_cast<size_t>(Level::FATAL));
        }

        bool Logger::AddSink(shared_ptr<Sink> const &new_sink)
        {
            m_mutex->lock();

            for(size_t i=0; i < m_list_sinks.size(); i++) {
                shared_ptr<Sink> const &sink =
                        m_list_sinks[i];

                if(sink == new_sink) {
                    m_mutex->unlock();
                    return false;
                }
            }

            m_list_sinks.push_back(new_sink);

            m_mutex->unlock();
            return true;
        }

        bool Logger::RemoveSink(shared_ptr<Sink> const &sink)
        {
            m_mutex->lock();

            for(auto sink_it = m_list_sinks.begin();
                sink_it != m_list_sinks.end();
                ++sink_it)
            {
                if((*sink_it) == sink) {
                    m_list_sinks.erase(sink_it);
                    m_mutex->unlock();
                    return true;
                }
            }
            m_mutex->unlock();
            return false;
        }

        void Logger::SetLevel(Level level)
        {
            m_mutex->lock();
            m_filter.set(static_cast<size_t>(level));
            m_mutex->unlock();
        }

        void Logger::UnsetLevel(Level level)
        {
            m_mutex->lock();
            m_filter.reset(static_cast<size_t>(level));
            m_mutex->unlock();
        }

        void Logger::AddFormatBlock(unique_ptr<FormatBlock> fb,
                                    Level level)
        {
            m_mutex->lock();
            m_list_fb[static_cast<size_t>(level)].push_back(
                        std::move(fb));
            m_mutex->unlock();
        }

        // logging methods
        Logger::Line Logger::Custom(Level level)
        {
            m_mutex->lock();

            size_t const level_int = static_cast<size_t>(level);

            return Line(&m_list_sinks,
                        &(m_list_fb[level_int]),
                        m_mutex.get(),
                        m_filter[level_int]);
        }

        Logger::Line Logger::Trace()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::TRACE);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Debug()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::DEBUG);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Info()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::INFO);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Warn()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::WARN);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Error()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::ERROR);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Fatal()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::FATAL);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        // ============================================================= //

    } // Log

    Log::Logger LOG(
            true, // thread-safe
#ifdef KS_ENV_ANDROID
            make_shared<Log::SinkToLogCat>(),
#else
            make_shared<Log::SinkToStdOut>(), // log to stdout by default
#endif
//            {{ // array init-list
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": TRACE: KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": DEBUG: KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": INFO:  KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": WARN:  KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": ERROR: KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": FATAL: KS: ") }
//             }});

            {{ // array init-list
               { new Log::FBCustomStr("TRACE: KS: ") },
               { new Log::FBCustomStr("DEBUG: KS: ") },
               { new Log::FBCustomStr("INFO:  KS: ") },
               { new Log::FBCustomStr("WARN:  KS: ") },
               { new Log::FBCustomStr("ERROR: KS: ") },
               { new Log::FBCustomStr("FATAL: KS: ") }
             }});

} // ks
<commit_msg>Log: fixed include header typo for android log<commit_after>/*
   Copyright (C) 2015 Preet Desai (preet.desai@gmail.com)

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include <ks/KsLog.hpp>

#ifdef KS_ENV_ANDROID
#include <android/log.h>
#endif

namespace ks
{
    namespace Log
    {
        #ifdef KS_ENV_ANDROID
            void SinkToLogCat::log(std::string const &line)
            {
                m_mutex.lock();
                __android_log_print(ANDROID_LOG_VERBOSE,"ks",line.c_str());
                m_mutex.unlock();
            }
        #endif

        // ============================================================= //

        FBRunTimeMs::FBRunTimeMs() :
            m_time_str("00:00:00.000"),
            m_start(std::chrono::system_clock::now()),
            m_list_num_chars({{'0','1','2','3','4','5','6','7','8','9'}})
        {
            // empty
        }

        FBRunTimeMs::~FBRunTimeMs()
        {
            // empty
        }

        std::string FBRunTimeMs::Get()
        {
            // TODO: should we use steady_clock, not system clock?
            auto now = std::chrono::system_clock::now();
            std::chrono::system_clock::duration elapsed = now-m_start;

            std::chrono::hours hours =
                    std::chrono::duration_cast<std::chrono::hours>(
                        elapsed);
            elapsed -= hours;

            std::chrono::minutes mins =
                    std::chrono::duration_cast<std::chrono::minutes>(
                        elapsed);
            elapsed -= mins;

            std::chrono::seconds secs =
                    std::chrono::duration_cast<std::chrono::seconds>(
                        elapsed);
            elapsed -= secs;

            std::chrono::milliseconds ms =
                    std::chrono::duration_cast<std::chrono::milliseconds>(
                        elapsed);

            uint_fast8_t const hours_count = hours.count();
            uint_fast8_t const mins_count = mins.count();
            uint_fast8_t const secs_count = secs.count();
            uint_fast16_t const ms_count = ms.count();

            m_time_str[0] = m_list_num_chars[hours_count/10];
            m_time_str[1] = m_list_num_chars[hours_count%10];

            m_time_str[3] = m_list_num_chars[mins_count/10];
            m_time_str[4] = m_list_num_chars[mins_count%10];

            m_time_str[6] = m_list_num_chars[secs_count/10];
            m_time_str[7] = m_list_num_chars[secs_count%10];

            m_time_str[9] = m_list_num_chars[ms_count/100];
            m_time_str[10] = m_list_num_chars[(ms_count%100)/10];
            m_time_str[11] = m_list_num_chars[(ms_count%100)%10];

            return m_time_str;
        }

        FBCustomStr::FBCustomStr(std::string const &s) : m_s(s)
        {
            // empty
        }

        FBCustomStr::~FBCustomStr()
        {
            // empty
        }

        std::string FBCustomStr::Get()
        {
            return m_s;
        }

        // ============================================================= //

        Logger::Logger()
        {
            m_mutex = make_unique<MutexSTL>();

            // default filter is all on
            m_filter.set(static_cast<size_t>(Level::TRACE));
            m_filter.set(static_cast<size_t>(Level::DEBUG));
            m_filter.set(static_cast<size_t>(Level::INFO));
            m_filter.set(static_cast<size_t>(Level::WARN));
            m_filter.set(static_cast<size_t>(Level::ERROR));
            m_filter.set(static_cast<size_t>(Level::FATAL));
        }

        Logger::Logger(bool thread_safe,
                       shared_ptr<Sink> const &sink,
                       std::array<std::vector<FormatBlock*>,6> && list_fbs)
        {
            if(thread_safe) {
                m_mutex = make_unique<MutexSTL>();
            }
            else {
                m_mutex = make_unique<MutexDummy>();
            }

            // save sink
            m_list_sinks.push_back(sink);

            // save format blocks
            for(uint level=0; level < 6; level++) {
                for(uint fb_idx=0; fb_idx < list_fbs[level].size(); fb_idx++) {
                    m_list_fb[level].push_back(
                                std::move(unique_ptr<FormatBlock>(
                                              list_fbs[level][fb_idx])));
                }
            }

            // default filter is all on
            m_filter.set(static_cast<size_t>(Level::TRACE));
            m_filter.set(static_cast<size_t>(Level::DEBUG));
            m_filter.set(static_cast<size_t>(Level::INFO));
            m_filter.set(static_cast<size_t>(Level::WARN));
            m_filter.set(static_cast<size_t>(Level::ERROR));
            m_filter.set(static_cast<size_t>(Level::FATAL));
        }

        bool Logger::AddSink(shared_ptr<Sink> const &new_sink)
        {
            m_mutex->lock();

            for(size_t i=0; i < m_list_sinks.size(); i++) {
                shared_ptr<Sink> const &sink =
                        m_list_sinks[i];

                if(sink == new_sink) {
                    m_mutex->unlock();
                    return false;
                }
            }

            m_list_sinks.push_back(new_sink);

            m_mutex->unlock();
            return true;
        }

        bool Logger::RemoveSink(shared_ptr<Sink> const &sink)
        {
            m_mutex->lock();

            for(auto sink_it = m_list_sinks.begin();
                sink_it != m_list_sinks.end();
                ++sink_it)
            {
                if((*sink_it) == sink) {
                    m_list_sinks.erase(sink_it);
                    m_mutex->unlock();
                    return true;
                }
            }
            m_mutex->unlock();
            return false;
        }

        void Logger::SetLevel(Level level)
        {
            m_mutex->lock();
            m_filter.set(static_cast<size_t>(level));
            m_mutex->unlock();
        }

        void Logger::UnsetLevel(Level level)
        {
            m_mutex->lock();
            m_filter.reset(static_cast<size_t>(level));
            m_mutex->unlock();
        }

        void Logger::AddFormatBlock(unique_ptr<FormatBlock> fb,
                                    Level level)
        {
            m_mutex->lock();
            m_list_fb[static_cast<size_t>(level)].push_back(
                        std::move(fb));
            m_mutex->unlock();
        }

        // logging methods
        Logger::Line Logger::Custom(Level level)
        {
            m_mutex->lock();

            size_t const level_int = static_cast<size_t>(level);

            return Line(&m_list_sinks,
                        &(m_list_fb[level_int]),
                        m_mutex.get(),
                        m_filter[level_int]);
        }

        Logger::Line Logger::Trace()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::TRACE);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Debug()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::DEBUG);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Info()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::INFO);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Warn()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::WARN);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Error()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::ERROR);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        Logger::Line Logger::Fatal()
        {
            m_mutex->lock();

            size_t const level = static_cast<size_t>(Level::FATAL);

            return Line(&m_list_sinks,
                        &(m_list_fb[level]),
                        m_mutex.get(),
                        m_filter[level]);
        }

        // ============================================================= //

    } // Log

    Log::Logger LOG(
            true, // thread-safe
#ifdef KS_ENV_ANDROID
            make_shared<Log::SinkToLogCat>(),
#else
            make_shared<Log::SinkToStdOut>(), // log to stdout by default
#endif
//            {{ // array init-list
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": TRACE: KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": DEBUG: KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": INFO:  KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": WARN:  KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": ERROR: KS: ") },
//               { new Log::FBRunTimeMs(), new Log::FBCustomStr(": FATAL: KS: ") }
//             }});

            {{ // array init-list
               { new Log::FBCustomStr("TRACE: KS: ") },
               { new Log::FBCustomStr("DEBUG: KS: ") },
               { new Log::FBCustomStr("INFO:  KS: ") },
               { new Log::FBCustomStr("WARN:  KS: ") },
               { new Log::FBCustomStr("ERROR: KS: ") },
               { new Log::FBCustomStr("FATAL: KS: ") }
             }});

} // ks
<|endoftext|>


<commit_before>#pragma once

#include <DO/Sara/Core/EigenExtension.hpp>

namespace DO { namespace Sara {

  struct EightPointAlgorithm
  {
    template <typename Sample>
    Matrix3d operator()(const Sample&)
    {
      return Matrix3d{};
    }
  };

} /* namespace Sara */
} /* namespace DO */
<commit_msg>WIP: save work.<commit_after>#pragma once

#include <DO/Sara/Core/EigenExtension.hpp>

namespace DO { namespace Sara {

  inline void eight_point_alg_fundamental(const MatrixXd& x, const MatrixXd& y,
                                          Matrix3d& F)
  {
    Matrix<double, 8, 9> A(8, 9);

    for (int i = 0; i < 8; ++i)
      A.row(i) <<                          //
          x(i, 0) * y.col(i).transpose(),  //
          x(i, 1) * y.col(0).transpose(),  //
          y.col(i).transpose();

    Eigen::JacobiSVD<MatrixXd> svd(A);
    Matrix<double, 9, 1> S = svd.singularValues();
    Matrix<double, 9, 1> f = svd.matrixV().col(8);

    F.col(0) = f.block(0, 0, 1, 3);
    F.col(1) = f.block(3, 0, 1, 3);
    F.col(2) = f.block(6, 0, 1, 3);
  }

  inline void eight_point_alg_homography(const MatrixXd& x, const MatrixXd& y,
                                         Matrix3d& H)
  {
    const Vector2d p1 = x.col(0);
    const Vector2d p2 = x.col(1);
    const Vector2d p3 = x.col(2);
    const Vector2d p4 = x.col(3);

    const Vector2d q1 = y.col(0);
    const Vector2d q2 = y.col(1);
    const Vector2d q3 = y.col(2);
    const Vector2d q4 = y.col(3);

    using T = double;

    Matrix<double, 8, 8> M;
    M <<
    p1.x(), p1.y(), T(1),   T(0),   T(0), T(0), -p1.x()*q1.x(), -p1.y()*q1.x(),
      T(0),   T(0), T(0), p1.x(), p1.y(), T(1), -p1.x()*q1.y(), -p1.y()*q1.y(),
    p2.x(), p2.y(), T(1),   T(0),   T(0), T(0), -p2.x()*q2.x(), -p2.y()*q2.x(),
      T(0),   T(0), T(0), p2.x(), p2.y(), T(1), -p2.x()*q2.y(), -p2.y()*q2.y(),
    p3.x(), p3.y(), T(1),   T(0),   T(0), T(0), -p3.x()*q3.x(), -p3.y()*q3.x(),
      T(0),   T(0), T(0), p3.x(), p3.y(), T(1), -p3.x()*q3.y(), -p3.y()*q3.y(),
    p4.x(), p4.y(), T(1),   T(0),   T(0), T(0), -p4.x()*q4.x(), -p4.y()*q4.x(),
      T(0),   T(0), T(0), p4.x(), p4.y(), T(1), -p4.x()*q4.y(), -p4.y()*q4.y();

    Matrix<double, 8, 1> b;
    b << q1.x(), q1.y(), q2.x(), q2.y(), q3.x(), q3.y(), q4.x(), q4.y();

    Matrix<T, 8, 1> h(M.colPivHouseholderQr().solve(b));

    H << h[0], h[1], h[2],
         h[3], h[4], h[5],
         h[6], h[7], 1.0;
  }

} /* namespace Sara */
} /* namespace DO */
<|endoftext|>


<commit_before>/*
  ePaper.cpp
  2013 Copyright (c) Seeed Technology Inc.  All right reserved.

  Modified by Loovee
  www.seeedstudio.com
  2013-7-2

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

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

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <Arduino.h>
#include <SPI.h>
#include "GT20L16_drive.h"
#include "ePaper.h"

static void spi_on()
{
    SPI.begin();
    //SPI.setClockDivider(SPI_CLOCK_DIV2);
    //SPI_put(0x00);
    //SPI_put(0x00);
}

/*********************************************************************************************************
* \brief According to EPD size and temperature to get stage_time
* \note Refer to COG document Section 5.3 for more details
*
* \param EPD_type_index The defined EPD size
**********************************************************************************************************/
void ePaper::begin(EPD_size sz)
{
    size = sz;
    direction = DIRNORMAL;

    switch(size)
    {
        case EPD_1_44:              // 128*96
        SIZE_LEN    = 128;
        SIZE_WIDTH  = 96;
        break;

        case EPD_2_0:               // 200*96
        SIZE_LEN    = 200;
        SIZE_WIDTH  = 96;
        break;

        case EPD_2_7:               // 264*176
        SIZE_LEN    = 264;
        SIZE_WIDTH  = 176;
        break;

        default:
        println_ep("wrong size");
        while(1);                   // die here
    }

    EPD.begin(size);
    init_io();
}

void ePaper::spi_detach()
{
}
/*********************************************************************************************************
** Function name:           begin
** Descriptions:            begin
*********************************************************************************************************/
void ePaper::setDirection(EPD_DIR dir)
{
    direction = dir;

    if((direction == DIRLEFT) || (direction == DIRRIGHT))
    {
        DISP_LEN    = SIZE_WIDTH;
        DISP_WIDTH  = SIZE_LEN;
    }

    eSD.setDirection(direction);
}
/*********************************************************************************************************
** Function name:           start
** Descriptions:            start
*********************************************************************************************************/
void ePaper::start()
{
    EPD.start();                 // power up the EPD panel

    int tmp = getTemperature();
    Serial.print("temperature: ");
    EPD.setFactor(getTemperature());         // adjust for current temperature
}

/*********************************************************************************************************
** Function name:           end
** Descriptions:            end
*********************************************************************************************************/
void ePaper::end()
{
    EPD.end();
}

/*********************************************************************************************************
** Function name:           init_io
** Descriptions:            init IO
*********************************************************************************************************/
void ePaper::init_io()
{
    // init IO
    pinMode(Pin_BUSY, INPUT);
    pinMode(Pin_RESET, OUTPUT);
    pinMode(Pin_PANEL_ON, OUTPUT);
    pinMode(Pin_DISCHARGE, OUTPUT);
    pinMode(Pin_BORDER, OUTPUT);
    pinMode(Pin_EPD_CS, OUTPUT);
    pinMode(Pin_SD_CS, OUTPUT);

    pinMode(9, OUTPUT);
    digitalWrite(9, HIGH);

    digitalWrite(Pin_RESET, LOW);
    digitalWrite(Pin_PANEL_ON, LOW);
    digitalWrite(Pin_DISCHARGE, LOW);
    digitalWrite(Pin_BORDER, LOW);
    digitalWrite(Pin_EPD_CS, HIGH);
    digitalWrite(Pin_SD_CS, HIGH);

    // init SPI
    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    //SPI.setClockDivider(SPI_CLOCK_DIV2);
}

/*********************************************************************************************************
** Function name:           getTemperature
** Descriptions:            get temperature of sensor
*********************************************************************************************************/
int ePaper::getTemperature()
{
    int sum = 0;
    for(int i=0; i<32; i++)
    {
        sum += analogRead(Pin_TEMPERATURE);
    }
    sum  = sum >> 5;

    float temp = 209.56-121.7*(float(sum)/1023.0*5.0);

    return (int)temp;
}

/*********************************************************************************************************
** Function name:           drawUnicode
** Descriptions:            draw a unicode
*********************************************************************************************************/
int ePaper::drawUnicode(unsigned int uniCode, int x, int y)
{

   // if(((x+16)>= DISP_LEN) || ((y+16) >= DISP_WIDTH) || x<0 || y<0) return 0;

    int dtaLen = GT20L16.getMatrixUnicode(uniCode, tMatrix);

    int pX      = 0;
    int pY      = 0;
    int color   = 0;
    //spi_on();
    for(int k = 0; k<2; k++)
    {
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<(dtaLen/2); j++)
            {

                if(tMatrix[j+(dtaLen/2)*k] & (0x01<<(7-i)))
                {
                    color = 1;
                }
                else
                {
                    color = 0;
                }

                pX = x + j;
                pY = y + k*8+i;

                drawPixel(pX, pY, color);
            }
        }
    }

    return dtaLen/2;        // x +
}

int ePaper::drawUnicode(unsigned char *matrix, int x, int y)
{

   // if(((x+16)>= DISP_LEN) || ((y+16) >= DISP_WIDTH) || x<0 || y<0) return 0;

    int dtaLen  = 32;
    int pX      = 0;
    int pY      = 0;
    int color   = 0;
    //spi_on();
    for(int k = 0; k<2; k++)
    {
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<(dtaLen/2); j++)
            {

                if(matrix[j+(dtaLen/2)*k] & (0x01<<(7-i)))
                {
                    color = 1;
                }
                else
                {
                    color = 0;
                }

                pX = x + j;
                pY = y + k*8+i;

                drawPixel(pX, pY, color);
            }
        }
    }

    return dtaLen/2;        // x +
}

/*********************************************************************************************************
** Function name:           drawUnicodeString
** Descriptions:            draw string
*********************************************************************************************************/
int ePaper::drawUnicodeString(unsigned int *uniCode, int len, int x, int y)
{
    int xPlus = 0;
    int xSum  = 0;

    for(int i=0; i<len; i++)
    {
        xPlus = drawUnicode(uniCode[i], x, y);
        x += xPlus;
        xSum += xPlus;
    }
    return xSum;
}

/*********************************************************************************************************
** Function name:           drawChar
** Descriptions:            draw char
*********************************************************************************************************/
int ePaper::drawChar(char c, int x, int y)
{
    return drawUnicode(c, x, y);
}

/*********************************************************************************************************
** Function name:           drawString
** Descriptions:            draw string
*********************************************************************************************************/
int ePaper::drawString(char *string, int poX, int poY)
{
    int sumX = 0;

    while(*string)
    {

        int xPlus = drawChar(*string, poX, poY);
        sumX += xPlus;
        *string++;

        if(poX < 200)
        {
            poX += xPlus;                                     /* Move cursor right            */
        }
    }

    return sumX;
}

/*********************************************************************************************************
** Function name:           drawNumber
** Descriptions:            drawNumber
*********************************************************************************************************/
int ePaper::drawNumber(long long_num,int poX, int poY)
{
    char tmp[10];
    sprintf(tmp, "%d", long_num);
    return drawString(tmp, poX, poY);

}

/*********************************************************************************************************
** Function name:           drawFloat
** Descriptions:            drawFloat
*********************************************************************************************************/
int ePaper::drawFloat(float floatNumber, int decimal, int poX, int poY)
{
    unsigned long temp=0;
    float decy=0.0;
    float rounding = 0.5;
    unsigned char f=0;

    float eep = 0.000001;

    int sumX    = 0;
    int xPlus   = 0;

    if(floatNumber-0.0 < eep)       // floatNumber < 0
    {
        xPlus = drawChar('-',poX, poY);
        floatNumber = -floatNumber;

        poX  += xPlus;
        sumX += xPlus;
    }

    for (unsigned char i=0; i<decimal; ++i)
    {
        rounding /= 10.0;
    }

    floatNumber += rounding;

    temp = (long)floatNumber;

    xPlus = drawNumber(temp,poX, poY);

    poX  += xPlus;
    sumX += xPlus;

    if(decimal>0)
    {
        xPlus = drawChar('.',poX, poY);
        poX += xPlus;                                       /* Move cursor right            */
        sumX += xPlus;
    }
    else
    {
        return sumX;
    }

    decy = floatNumber - temp;
    for(unsigned char i=0; i<decimal; i++)
    {
        decy *= 10;                                                      /* for the next decimal         */
        temp = decy;                                                    /* get the decimal              */
        xPlus = drawNumber(temp,poX, poY);

        poX += xPlus;                                       /* Move cursor right            */
        sumX += xPlus;
        decy -= temp;
    }
    return sumX;
}

/*********************************************************************************************************
** Function name:           drawLine
** Descriptions:            drawLine
*********************************************************************************************************/
void ePaper::drawLine(int x0, int y0, int x1, int y1)
{

    init_io();

    int x = x1-x0;
    int y = y1-y0;
    int dx = abs(x), sx = x0<x1 ? 1 : -1;
    int dy = -abs(y), sy = y0<y1 ? 1 : -1;
    int err = dx+dy, e2;
    for (;;)
    {
        drawPixel(x0,y0,1);
        e2 = 2*err;
        if (e2 >= dy)
        {
            if (x0 == x1) break;
            err += dy; x0 += sx;
        }
        if (e2 <= dx)
        {
            if (y0 == y1) break;
            err += dx; y0 += sy;
        }
    }
}

/*********************************************************************************************************
** Function name:           clear_sd
** Descriptions:            clear sd card
*********************************************************************************************************/
void ePaper::clear_sd()
{

    init_io();

    for(int i=0; i<DISP_WIDTH; i++)
    {
        for(int j=0; j<DISP_LEN; j++)
        {
            drawPixel(j, i, 0);

        }
    }
}

/*********************************************************************************************************
** Function name:           drawCircle
** Descriptions:            drawCircle
*********************************************************************************************************/
void ePaper::drawCircle(int poX, int poY, int r)
{

    init_io();
    int x = -r, y = 0, err = 2-2*r, e2;
    do {
        drawPixel(poX-x, poY+y, 1);
        drawPixel(poX+x, poY+y, 1);
        drawPixel(poX+x, poY-y, 1);
        drawPixel(poX-x, poY-y, 1);
        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);
}

/*********************************************************************************************************
** Function name:           drawHorizontalLine
** Descriptions:            drawHorizontalLine
*********************************************************************************************************/
void ePaper::drawHorizontalLine( int poX, int poY, int len)
{
    drawLine(poX, poY, poX+len, poY);
}

/*********************************************************************************************************
** Function name:           drawVerticalLine
** Descriptions:            drawVerticalLine
*********************************************************************************************************/
void ePaper::drawVerticalLine( int poX, int poY, int len)
{
    drawLine(poX, poY, poX, poY+len);
}

/*********************************************************************************************************
** Function name:           drawRectangle
** Descriptions:            drawRectangle
*********************************************************************************************************/
void ePaper::drawRectangle(int poX, int poY, int len, int width)
{
    drawHorizontalLine(poX, poY, len);
    drawHorizontalLine(poX, poY+width, len);
    drawVerticalLine(poX, poY, width);
    drawVerticalLine(poX + len, poY, width);
}

/*********************************************************************************************************
** Function name:           fillCircle
** Descriptions:            fillCircle
*********************************************************************************************************/
void ePaper::fillCircle(int poX, int poY, int r)
{
    int x = -r, y = 0, err = 2-2*r, e2;

    do {

        drawVerticalLine(poX-x, poY-y, 2*y);
        drawVerticalLine(poX+x, poY-y, 2*y);

        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);

}

/*********************************************************************************************************
** Function name:           drawTraingle
** Descriptions:            drawTraingle
*********************************************************************************************************/
void ePaper::drawTraingle( int poX1, int poY1, int poX2, int poY2, int poX3, int poY3)
{
    drawLine(poX1, poY1, poX2, poY2);
    drawLine(poX1, poY1, poX3, poY3);
    drawLine(poX2, poY2, poX3, poY3);
}

/*********************************************************************************************************
** Function name:           drawTraingle
** Descriptions:            drawTraingle
*********************************************************************************************************/
void ePaper::fillRectangle(int poX, int poY, int len, int width)
{
    for(int i=0; i<width; i++)
    {
        drawHorizontalLine(poX, poY+i, len);
    }
}

/*********************************************************************************************************
** Function name:           display
** Descriptions:            you should use this function once after finish drawing
*********************************************************************************************************/
unsigned char ePaper::display()
{
    start();
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__)
    EPD.image_sd();
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    EPD.image_sram(eSD.sram_image);
#endif
    end();
}

ePaper EPAPER;
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/
<commit_msg>Fixed additional problems<commit_after>/*
  ePaper.cpp
  2013 Copyright (c) Seeed Technology Inc.  All right reserved.

  Modified by Loovee
  www.seeedstudio.com
  2013-7-2

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

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

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <Arduino.h>
#include <SPI.h>
#include "GT20L16_drive.h"
#include "ePaper.h"

static void spi_on()
{
    SPI.begin();
    //SPI.setClockDivider(SPI_CLOCK_DIV2);
    //SPI_put(0x00);
    //SPI_put(0x00);
}

/*********************************************************************************************************
* \brief According to EPD size and temperature to get stage_time
* \note Refer to COG document Section 5.3 for more details
*
* \param EPD_type_index The defined EPD size
**********************************************************************************************************/
void ePaper::begin(EPD_size sz)
{
    size = sz;
    direction = DIRNORMAL;

    switch(size)
    {
        case EPD_1_44:              // 128*96
        SIZE_LEN    = 128;
        SIZE_WIDTH  = 96;
        break;

        case EPD_2_0:               // 200*96
        SIZE_LEN    = 200;
        SIZE_WIDTH  = 96;
        break;

        case EPD_2_7:               // 264*176
        SIZE_LEN    = 264;
        SIZE_WIDTH  = 176;
        break;

        default:
        println_ep("wrong size");
        while(1);                   // die here
    }

    DISP_LEN    = SIZE_LEN;
    DISP_WIDTH  = SIZE_WIDTH;

    EPD.begin(size);
    init_io();
}

void ePaper::spi_detach()
{
}
/*********************************************************************************************************
** Function name:           begin
** Descriptions:            begin
*********************************************************************************************************/
void ePaper::setDirection(EPD_DIR dir)
{
    direction = dir;

    if((direction == DIRLEFT) || (direction == DIRRIGHT))
    {
        DISP_LEN    = SIZE_WIDTH;
        DISP_WIDTH  = SIZE_LEN;
    }

    eSD.setDirection(direction);
}
/*********************************************************************************************************
** Function name:           start
** Descriptions:            start
*********************************************************************************************************/
void ePaper::start()
{
    EPD.start();                 // power up the EPD panel

    int tmp = getTemperature();
    Serial.print("temperature: ");
    EPD.setFactor(getTemperature());         // adjust for current temperature
}

/*********************************************************************************************************
** Function name:           end
** Descriptions:            end
*********************************************************************************************************/
void ePaper::end()
{
    EPD.end();
}

/*********************************************************************************************************
** Function name:           init_io
** Descriptions:            init IO
*********************************************************************************************************/
void ePaper::init_io()
{
    // init IO
    pinMode(Pin_BUSY, INPUT);
    pinMode(Pin_RESET, OUTPUT);
    pinMode(Pin_PANEL_ON, OUTPUT);
    pinMode(Pin_DISCHARGE, OUTPUT);
    pinMode(Pin_BORDER, OUTPUT);
    pinMode(Pin_EPD_CS, OUTPUT);
    pinMode(Pin_SD_CS, OUTPUT);

    pinMode(9, OUTPUT);
    digitalWrite(9, HIGH);

    digitalWrite(Pin_RESET, LOW);
    digitalWrite(Pin_PANEL_ON, LOW);
    digitalWrite(Pin_DISCHARGE, LOW);
    digitalWrite(Pin_BORDER, LOW);
    digitalWrite(Pin_EPD_CS, HIGH);
    digitalWrite(Pin_SD_CS, HIGH);

    // init SPI
    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    //SPI.setClockDivider(SPI_CLOCK_DIV2);
}

/*********************************************************************************************************
** Function name:           getTemperature
** Descriptions:            get temperature of sensor
*********************************************************************************************************/
int ePaper::getTemperature()
{
    int sum = 0;
    for(int i=0; i<32; i++)
    {
        sum += analogRead(Pin_TEMPERATURE);
    }
    sum  = sum >> 5;

    float temp = 209.56-121.7*(float(sum)/1023.0*5.0);

    return (int)temp;
}

/*********************************************************************************************************
** Function name:           drawUnicode
** Descriptions:            draw a unicode
*********************************************************************************************************/
int ePaper::drawUnicode(unsigned int uniCode, int x, int y)
{

   // if(((x+16)>= DISP_LEN) || ((y+16) >= DISP_WIDTH) || x<0 || y<0) return 0;

    int dtaLen = GT20L16.getMatrixUnicode(uniCode, tMatrix);

    int pX      = 0;
    int pY      = 0;
    int color   = 0;
    //spi_on();
    for(int k = 0; k<2; k++)
    {
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<(dtaLen/2); j++)
            {

                if(tMatrix[j+(dtaLen/2)*k] & (0x01<<(7-i)))
                {
                    color = 1;
                }
                else
                {
                    color = 0;
                }

                pX = x + j;
                pY = y + k*8+i;

                drawPixel(pX, pY, color);
            }
        }
    }

    return dtaLen/2;        // x +
}

int ePaper::drawUnicode(unsigned char *matrix, int x, int y)
{

   // if(((x+16)>= DISP_LEN) || ((y+16) >= DISP_WIDTH) || x<0 || y<0) return 0;

    int dtaLen  = 32;
    int pX      = 0;
    int pY      = 0;
    int color   = 0;
    //spi_on();
    for(int k = 0; k<2; k++)
    {
        for(int i=0; i<8; i++)
        {
            for(int j=0; j<(dtaLen/2); j++)
            {

                if(matrix[j+(dtaLen/2)*k] & (0x01<<(7-i)))
                {
                    color = 1;
                }
                else
                {
                    color = 0;
                }

                pX = x + j;
                pY = y + k*8+i;

                drawPixel(pX, pY, color);
            }
        }
    }

    return dtaLen/2;        // x +
}

/*********************************************************************************************************
** Function name:           drawUnicodeString
** Descriptions:            draw string
*********************************************************************************************************/
int ePaper::drawUnicodeString(unsigned int *uniCode, int len, int x, int y)
{
    int xPlus = 0;
    int xSum  = 0;

    for(int i=0; i<len; i++)
    {
        xPlus = drawUnicode(uniCode[i], x, y);
        x += xPlus;
        xSum += xPlus;
    }
    return xSum;
}

/*********************************************************************************************************
** Function name:           drawChar
** Descriptions:            draw char
*********************************************************************************************************/
int ePaper::drawChar(char c, int x, int y)
{
    return drawUnicode(c, x, y);
}

/*********************************************************************************************************
** Function name:           drawString
** Descriptions:            draw string
*********************************************************************************************************/
int ePaper::drawString(char *string, int poX, int poY)
{
    int sumX = 0;

    while(*string)
    {

        int xPlus = drawChar(*string, poX, poY);
        sumX += xPlus;
        *string++;

        if(poX < 200)
        {
            poX += xPlus;                                     /* Move cursor right            */
        }
    }

    return sumX;
}

/*********************************************************************************************************
** Function name:           drawNumber
** Descriptions:            drawNumber
*********************************************************************************************************/
int ePaper::drawNumber(long long_num,int poX, int poY)
{
    char tmp[10];
    sprintf(tmp, "%d", long_num);
    return drawString(tmp, poX, poY);

}

/*********************************************************************************************************
** Function name:           drawFloat
** Descriptions:            drawFloat
*********************************************************************************************************/
int ePaper::drawFloat(float floatNumber, int decimal, int poX, int poY)
{
    unsigned long temp=0;
    float decy=0.0;
    float rounding = 0.5;
    unsigned char f=0;

    float eep = 0.000001;

    int sumX    = 0;
    int xPlus   = 0;

    if(floatNumber-0.0 < eep)       // floatNumber < 0
    {
        xPlus = drawChar('-',poX, poY);
        floatNumber = -floatNumber;

        poX  += xPlus;
        sumX += xPlus;
    }

    for (unsigned char i=0; i<decimal; ++i)
    {
        rounding /= 10.0;
    }

    floatNumber += rounding;

    temp = (long)floatNumber;

    xPlus = drawNumber(temp,poX, poY);

    poX  += xPlus;
    sumX += xPlus;

    if(decimal>0)
    {
        xPlus = drawChar('.',poX, poY);
        poX += xPlus;                                       /* Move cursor right            */
        sumX += xPlus;
    }
    else
    {
        return sumX;
    }

    decy = floatNumber - temp;
    for(unsigned char i=0; i<decimal; i++)
    {
        decy *= 10;                                                      /* for the next decimal         */
        temp = decy;                                                    /* get the decimal              */
        xPlus = drawNumber(temp,poX, poY);

        poX += xPlus;                                       /* Move cursor right            */
        sumX += xPlus;
        decy -= temp;
    }
    return sumX;
}

/*********************************************************************************************************
** Function name:           drawLine
** Descriptions:            drawLine
*********************************************************************************************************/
void ePaper::drawLine(int x0, int y0, int x1, int y1)
{

    init_io();

    int x = x1-x0;
    int y = y1-y0;
    int dx = abs(x), sx = x0<x1 ? 1 : -1;
    int dy = -abs(y), sy = y0<y1 ? 1 : -1;
    int err = dx+dy, e2;
    for (;;)
    {
        drawPixel(x0,y0,1);
        e2 = 2*err;
        if (e2 >= dy)
        {
            if (x0 == x1) break;
            err += dy; x0 += sx;
        }
        if (e2 <= dx)
        {
            if (y0 == y1) break;
            err += dx; y0 += sy;
        }
    }
}

/*********************************************************************************************************
** Function name:           clear_sd
** Descriptions:            clear sd card
*********************************************************************************************************/
void ePaper::clear_sd()
{

    init_io();

    for(int i=0; i<DISP_WIDTH; i++)
    {
        for(int j=0; j<DISP_LEN; j++)
        {
            drawPixel(j, i, 0);

        }
    }
}

/*********************************************************************************************************
** Function name:           drawCircle
** Descriptions:            drawCircle
*********************************************************************************************************/
void ePaper::drawCircle(int poX, int poY, int r)
{

    init_io();
    int x = -r, y = 0, err = 2-2*r, e2;
    do {
        drawPixel(poX-x, poY+y, 1);
        drawPixel(poX+x, poY+y, 1);
        drawPixel(poX+x, poY-y, 1);
        drawPixel(poX-x, poY-y, 1);
        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);
}

/*********************************************************************************************************
** Function name:           drawHorizontalLine
** Descriptions:            drawHorizontalLine
*********************************************************************************************************/
void ePaper::drawHorizontalLine( int poX, int poY, int len)
{
    drawLine(poX, poY, poX+len, poY);
}

/*********************************************************************************************************
** Function name:           drawVerticalLine
** Descriptions:            drawVerticalLine
*********************************************************************************************************/
void ePaper::drawVerticalLine( int poX, int poY, int len)
{
    drawLine(poX, poY, poX, poY+len);
}

/*********************************************************************************************************
** Function name:           drawRectangle
** Descriptions:            drawRectangle
*********************************************************************************************************/
void ePaper::drawRectangle(int poX, int poY, int len, int width)
{
    drawHorizontalLine(poX, poY, len);
    drawHorizontalLine(poX, poY+width, len);
    drawVerticalLine(poX, poY, width);
    drawVerticalLine(poX + len, poY, width);
}

/*********************************************************************************************************
** Function name:           fillCircle
** Descriptions:            fillCircle
*********************************************************************************************************/
void ePaper::fillCircle(int poX, int poY, int r)
{
    int x = -r, y = 0, err = 2-2*r, e2;

    do {

        drawVerticalLine(poX-x, poY-y, 2*y);
        drawVerticalLine(poX+x, poY-y, 2*y);

        e2 = err;
        if (e2 <= y) {
            err += ++y*2+1;
            if (-x == y && e2 <= x) e2 = 0;
        }
        if (e2 > x) err += ++x*2+1;
    } while (x <= 0);

}

/*********************************************************************************************************
** Function name:           drawTraingle
** Descriptions:            drawTraingle
*********************************************************************************************************/
void ePaper::drawTraingle( int poX1, int poY1, int poX2, int poY2, int poX3, int poY3)
{
    drawLine(poX1, poY1, poX2, poY2);
    drawLine(poX1, poY1, poX3, poY3);
    drawLine(poX2, poY2, poX3, poY3);
}

/*********************************************************************************************************
** Function name:           drawTraingle
** Descriptions:            drawTraingle
*********************************************************************************************************/
void ePaper::fillRectangle(int poX, int poY, int len, int width)
{
    for(int i=0; i<width; i++)
    {
        drawHorizontalLine(poX, poY+i, len);
    }
}

/*********************************************************************************************************
** Function name:           display
** Descriptions:            you should use this function once after finish drawing
*********************************************************************************************************/
unsigned char ePaper::display()
{
    start();
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__)
    EPD.image_sd();
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    EPD.image_sram(eSD.sram_image);
#endif
    end();
}

ePaper EPAPER;
/*********************************************************************************************************
  END FILE
*********************************************************************************************************/
<|endoftext|>


<commit_before>#include "gibbs_sampler.hpp"
#include "distribution.hpp"
#include <vector>
#include <deque>

namespace mcmc_utilities
{

  template <typename T_p,typename T_stat,typename T_obs,typename T_t>
  class pf_model
  {
  private:
    pf_model(const pf_model&);
  public:
    typedef typename element_type_trait<T_stat>::element_type stat_element_type;
    typedef typename element_type_trait<T_obs>::element_type obs_element_type;
  public:
    pf_model(){}
    virtual ~pf_model(){}
    T_p evol_log_prob(const T_stat& x,const T_t& t,const std::deque<T_stat>& prev_stat,const std::deque<T_t>& prev_t)const
    {
      return do_evol_log_prob(x,t,prev_stat,prev_t);
	}

    T_p obs_log_prob(const T_obs& y,const T_stat& x,const T_t& t)const
    {
      return do_obs_log_prob(y,x,t);
    }

    void stat_var_range(T_stat& x1,T_stat& x2)const
    {
      return do_stat_var_range(x1,x2);
    }

  public:
    void update(const T_obs& y,const T_t& t,std::deque<T_stat>& prev_stat,std::deque<T_t>& prev_t)const
    {
      class cprob
	:public probability_density_md<T_p,T_stat>
      {
      private:
	const pf_model*  ptr_pf_model;
	const T_obs* ptr_obs_vec;
	const std::deque<T_stat>* ptr_prev_stat;
	const std::deque<T_t>* ptr_prev_t;
	const T_t* ptr_t;
	friend class pf_model;
      public:
	T_p do_eval_log(const T_stat& x)const
	{
	  return ptr_pf_model->evol_log_prob(x,*ptr_t,*ptr_prev_stat,*ptr_prev_t)+
	    ptr_pf_model->obs_log_prob(*ptr_obs_vec,x,*ptr_t);
	}
	cprob* do_clone()const
	{
	  return new cprob(*this);
	}

	void do_var_range(T_stat& x1,T_stat& x2)const
	{
	  ptr_pf_model->stat_var_range(x1,x2);
	}
      }prob;
      prob.ptr_pf_model=this;
      prob.ptr_obs_vec=&y;
      prob.ptr_prev_stat=&prev_stat;
      prob.ptr_prev_t=&prev_t;
      prob.ptr_t=&t;
      T_stat new_pred(prev_stat.back());
      gibbs_sample(prob,new_pred);
      prev_stat.push_back(new_pred);
      prev_t.push_back(t);
    }

  private:
    virtual T_p do_evol_log_prob(const T_stat& x,const T_t& t,const std::deque<T_stat>& prev_stat,const std::deque<T_t>& prev_t)const=0;
    virtual T_p do_obs_log_prob(const T_obs& y,const T_stat& x,const T_t& t)const=0;
    virtual void do_stat_var_range(T_stat& x1,T_stat& x2)const=0;
  };
};
<commit_msg>	修改：     core/particle_filter.hpp<commit_after>#include "gibbs_sampler.hpp"
#include "distribution.hpp"
#include <vector>
#include <deque>
namespace mcmc_utilities
{

  template <typename T_p,typename T_stat,typename T_obs,typename T_t>
  class pf_model
  {
  private:
    pf_model(const pf_model&);
  public:
    typedef typename element_type_trait<T_stat>::element_type stat_element_type;
    typedef typename element_type_trait<T_obs>::element_type obs_element_type;
  public:
    pf_model(){}
    virtual ~pf_model(){}
    T_p evol_log_prob(const T_stat& x,const T_t& t,const std::deque<T_stat>& prev_stat,const std::deque<T_t>& prev_t)const
    {
      return do_evol_log_prob(x,t,prev_stat,prev_t);
	}

    T_p obs_log_prob(const T_obs& y,const T_stat& x,const T_t& t)const
    {
      return do_obs_log_prob(y,x,t);
    }

    void stat_var_range(T_stat& x1,T_stat& x2)const
    {
      return do_stat_var_range(x1,x2);
    }

  public:
    void update(const T_obs& y,const T_t& t,std::deque<T_stat>& prev_stat,std::deque<T_t>& prev_t)const
    {
      class cprob
	:public probability_density_md<T_p,T_stat>
      {
      private:
	const pf_model*  ptr_pf_model;
	const T_obs* ptr_obs_vec;
	const std::deque<T_stat>* ptr_prev_stat;
	const std::deque<T_t>* ptr_prev_t;
	const T_t* ptr_t;
	friend class pf_model;
      public:
	T_p do_eval_log(const T_stat& x)const
	{
	  return ptr_pf_model->evol_log_prob(x,*ptr_t,*ptr_prev_stat,*ptr_prev_t)
	    +ptr_pf_model->obs_log_prob(*ptr_obs_vec,x,*ptr_t);
	}
	cprob* do_clone()const
	{
	  return new cprob(*this);
	}

	void do_var_range(T_stat& x1,T_stat& x2)const
	{
	  ptr_pf_model->stat_var_range(x1,x2);
	}
      }prob;
      prob.ptr_pf_model=this;
      prob.ptr_obs_vec=&y;
      prob.ptr_prev_stat=&prev_stat;
      prob.ptr_prev_t=&prev_t;
      prob.ptr_t=&t;
      T_stat new_pred(prev_stat.back());
      gibbs_sample(prob,new_pred);
      prev_stat.push_back(new_pred);
      prev_t.push_back(t);
    }

  private:
    virtual T_p do_evol_log_prob(const T_stat& x,const T_t& t,const std::deque<T_stat>& prev_stat,const std::deque<T_t>& prev_t)const=0;
    virtual T_p do_obs_log_prob(const T_obs& y,const T_stat& x,const T_t& t)const=0;
    virtual void do_stat_var_range(T_stat& x1,T_stat& x2)const=0;
  };
};
<|endoftext|>


<commit_before>/**
@file VarTemplate.hpp
@brief Var validation.

@author Tim Howard
@copyright 2010-2013 Tim Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

// TODO: infinitism

#ifndef DUCT_VARTEMPLATE_HPP_
#define DUCT_VARTEMPLATE_HPP_

#include "./config.hpp"
#include "./aux.hpp"
#include "./string.hpp"
#include "./StateStore.hpp"
#include "./VarType.hpp"
#include "./Var.hpp"

#include <utility>

namespace duct {

/**
	@addtogroup var
	@{
*/

/**
	Var validator.
*/
class VarTemplate {
public:
/** @name Types */ /// @{
	/**
		Layout field.
	*/
	struct Field {
	/** @name Types */ /// @{
		/**
			Field flags.

			@note See VarTemplate::validate_layout() for usage notes.
		*/
		enum class Flags : unsigned {
			/** No flags. */
			none = 0,

			/** Optional field. */
			optional = 1 << 0,
		};
	/// @}

	/** @name Properties */ /// @{
		/** Type mask. */
		VarMask mask;

		/** Flags. */
		StateStore<Flags> flags;

		/**
			Check if Flags::optional is enabled.
		*/
		bool
		optional() const noexcept {
			return flags.test(Flags::optional);
		}
	/// @}

	/** @name Constructors and destructor */ /// @{
		/** Destructor. */
		~Field() = default;
		/** Copy constructor. */
		Field(Field const&) = default;
		/** Move constructor. */
		Field(Field&&) = default;

		/**
			Construct with flags.

			@note Mask is VarMask::none.

			@param flags %Flags.
		*/
		Field(
			Flags const flags = Flags::none
		) noexcept
			: mask(VarMask::none)
			, flags(flags)
		{}

		/**
			Construct with type and flags.

			@param type Single-type mask.
			@param flags %Flags.
		*/
		Field(
			VarType const type,
			Flags const flags = Flags::none
		) noexcept
			: mask(var_mask(type))
			, flags(flags)
		{}

		/**
			Construct with mask and flags.

			@param mask Mask.
			@param flags %Flags.
		*/
		Field(
			VarMask const mask,
			Flags const flags = Flags::none
		) noexcept
			: mask(mask)
			, flags(flags)
		{}
	/// @}

	/** @name Operators */ /// @{
		/** Copy assignment operator. */
		Field& operator=(Field const&) = default;
		/** Move assignment operator. */
		Field& operator=(Field&&) = default;
	/// @}
	};

	/** Identity vector type. */
	using identity_vector_type = duct::aux::vector<u8string>;
	/** Layout vector type. */
	using layout_vector_type = duct::aux::vector<Field>;
/// @}

protected:
	/**
		%Flags.
	*/
	enum class Flags {
		/**
			Whether to permit empty collections in layout validation.

			@note This is enabled by default.
		*/
		permit_empty = 1 << 0
	};

	/** %Flags. */
	StateStore<Flags> m_flags{Flags::permit_empty};
	/** Type mask. */
	VarMask m_type_mask{VarMask::none};
	/** Identity. */
	identity_vector_type m_identity{};
	/** Layout. */
	layout_vector_type m_layout{};

public:
/** @name Constructors and destructor */ /// @{
	/**
		Construct with @c VarMask::none type mask, empty identity,
		and empty layout.
	*/
	VarTemplate() = default;

	/**
		Construct with type mask, empty identity, and empty layout.

		@param type_mask Type mask.
	*/
	explicit
	VarTemplate(
		VarMask const type_mask
	)
		: m_type_mask(type_mask)
	{}

	/**
		Construct with type mask, identity, and empty layout.

		@param type_mask Type mask.
		@param identity Identity.
	*/
	VarTemplate(
		VarMask const type_mask,
		identity_vector_type identity
	)
		: m_type_mask(type_mask)
		, m_identity(std::move(identity))
	{}

	/**
		Construct with type mask, layout, and empty identity.

		@param type_mask Type mask.
		@param layout Layout.
	*/
	VarTemplate(
		VarMask const type_mask,
		layout_vector_type layout
	)
		: m_type_mask(type_mask)
		, m_layout(std::move(layout))
	{}

	/**
		Construct with type mask, identity, and layout.

		@param type_mask Type mask.
		@param identity Identity.
		@param layout Layout.
	*/
	VarTemplate(
		VarMask const type_mask,
		identity_vector_type identity,
		layout_vector_type layout
	)
		: m_type_mask(type_mask)
		, m_identity(std::move(identity))
		, m_layout(std::move(layout))
	{}

	/** Copy constructor (deleted). */
	VarTemplate(VarTemplate const&) = delete;
	/** Move constructor. */
	VarTemplate(VarTemplate&&) = default;
	/** Destructor. */
	virtual ~VarTemplate() = default;
/// @}

/** @name Operators */ /// @{
	/** Copy assignment operator (deleted). */
	VarTemplate& operator=(VarTemplate const&) = delete;
	/** Move assignment operator. */
	VarTemplate& operator=(VarTemplate&&) = default;
/// @}

/** @name Properties */ /// @{
	/**
		Enable or disable flags.

		@param flags %Flags.
		@param enable Whether to enable or disable the flags.
	*/
	void
	set_flags(
		Flags const flags,
		bool const enable
	) noexcept {
		m_flags.set(flags, enable);
	}

	/**
		Check if Flags::permit_empty is enabled.
	*/
	bool
	permit_empty() const noexcept {
		return m_flags.test(Flags::permit_empty);
	}

	/**
		Set type mask.

		@param type_mask New type mask.
		@sa validate_type(Var const&) const
	*/
	void
	set_type_mask(
		VarMask const type_mask
	) noexcept {
		m_type_mask = type_mask;
	}

	/**
		Set type mask (single type).

		@param type New type mask.
		@sa validate_type(Var const&) const
	*/
	void
	set_type_mask(
		VarType const type
	) noexcept {
		m_type_mask = var_mask(type);
	}

	/**
		Get type mask.

		@returns The current type mask.
		@sa validate_type(Var const&) const
	*/
	VarMask
	get_type_mask() const noexcept {
		return m_type_mask;
	}

	/**
		Set identity.

		@param identity New identity.
		@sa validate_identity(Var const&) const
	*/
	void
	set_identity(
		identity_vector_type identity
	) {
		m_identity = std::move(identity);
	}

	/**
		Get identity.

		@returns The current identity.
		@sa validate_identity(Var const&) const
	*/
	identity_vector_type&
	get_identity() noexcept {
		return m_identity;
	}

	/** @copydoc get_identity() */
	identity_vector_type const&
	get_identity() const noexcept {
		return m_identity;
	}

	/**
		Set layout.

		@param layout New layout.
		@sa validate_layout(Var const&) const
	*/
	void
	set_layout(
		layout_vector_type layout
	) {
		m_layout = std::move(layout);
	}

	/**
		Get layout.

		@returns The current layout.
		@sa validate_layout(Var const&) const
	*/
	layout_vector_type&
	get_layout() noexcept {
		return m_layout;
	}

	/** @copydoc get_layout() */
	layout_vector_type const&
	get_layout() const noexcept {
		return m_layout;
	}

/// @}

/** @name Validation */ /// @{
	/**
		Validate a variable.

		@note If @c validate_type(var) is @c true, layout validation
		is only done if @a var is a collection.

		@returns @c true iff @a var matches template in type, identity,
		and layout.
		@param var Variable to validate.
		@sa validate_type(Var const&) const,
			validate_identity(Var const&) const,
			validate_layout(Var const&) const
	*/
	bool
	validate(
		Var const& var
	) const noexcept {
		return
			validate_type(var) &&
			validate_identity(var) &&
			(!var.is_type_of(VarMask::collection) || validate_layout(var))
		;
	}

	/**
		Validate a variable by type.

		@returns @c true iff bitwise-and of @a var type and template
		type mask is non-zero.
		@param var Variable to validate.
	*/
	virtual bool
	validate_type(
		Var const& var
	) const noexcept {
		return var_type_is_of(var.get_type(), m_type_mask);
	}

	/**
		Validate a variable by identity.

		@returns @c true iff:
		-# identity is empty (permits any name),
		-# variable name matches any name from identity
		   (including empty name).
		@param var Variable to validate.
	*/
	virtual bool
	validate_identity(
		Var const& var
	) const noexcept {
		if (m_identity.empty()) {
			// Any name is permitted with empty identity
			return true;
		} else {
			for (auto const& iname : get_identity()) {
				if (var.get_name() == iname) {
					// Variable name matches a name from identity
					return true;
				}
			}
			// Variable name does not match a name from identity
			return false;
		}
	}

	/**
		Validate a variable by layout.

		@note The @c Field::Flags::optional flag will cause all succeeding
		fields to be considered optional.
		@note The @c Field::Flags::empty flag is only considered when layout
		contains a single field.

		@returns
		- @c false iff:
			-# variable is not a @c VarMask::collection,
			-# variable has more children than layout;
		- @c true iff:
			-# layout is empty (permits any collection),
			-# layout contains a single field with flag
			   @c Field::Flags::empty and variable has no children,
			-# children sequentially match layout fields exactly,
			-# children sequentially match [0..var.size()] layout fields
			   if a field from [0..var.size()+1] is optional
			   (thus making all subsequent fields optional).
		@param var Variable to validate.
	*/
	virtual bool
	validate_layout(
		Var const& var
	) const noexcept {
		if (var.is_type_of(VarMask::collection)) {
			if (m_layout.empty()) {
				// Any collection is permitted with empty layout
				return permit_empty();
			} else if (var.size() > get_layout().size()) {
				// Collection cannot be larger than layout
				return false;
			} else {
				auto vc_iter = var.cbegin();
				auto lo_iter = get_layout().cbegin();
				bool optional_met = false;
				for (; var.cend() != vc_iter; ++vc_iter, ++lo_iter) {
					if (!vc_iter->is_type_of(lo_iter->mask)) {
						// Child type does not match field
						return false;
					} else if (!optional_met) {
						optional_met = lo_iter->optional();
					}
				}
				if (optional_met || get_layout().cend() == lo_iter) {
					// Collection sequentially matches layout fields
					// exactly or any trailing fields are optional
					return true;
				} else {
					// No optional field has been met, and there are
					// unchecked trailing field(s)
					if (lo_iter->optional()) {
						// First trailing field is optional (therefore
						// all following fields are optional)
						return true;
					} else {
						// First trailing field is not optional
						return false;
					}
				}
			}
		} else {
			// Variable is not a collection
			return false;
		}
	}
/// @}
};

/** @} */ // end of doc-group var

} // namespace duct

#endif // DUCT_VARTEMPLATE_HPP_
<commit_msg>VarTemplate: defaulted cctor and copy operator=().¹<commit_after>/**
@file VarTemplate.hpp
@brief Var validation.

@author Tim Howard
@copyright 2010-2013 Tim Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

// TODO: infinitism

#ifndef DUCT_VARTEMPLATE_HPP_
#define DUCT_VARTEMPLATE_HPP_

#include "./config.hpp"
#include "./aux.hpp"
#include "./string.hpp"
#include "./StateStore.hpp"
#include "./VarType.hpp"
#include "./Var.hpp"

#include <utility>

namespace duct {

/**
	@addtogroup var
	@{
*/

/**
	Var validator.
*/
class VarTemplate {
public:
/** @name Types */ /// @{
	/**
		Layout field.
	*/
	struct Field {
	/** @name Types */ /// @{
		/**
			Field flags.

			@note See VarTemplate::validate_layout() for usage notes.
		*/
		enum class Flags : unsigned {
			/** No flags. */
			none = 0,

			/** Optional field. */
			optional = 1 << 0,
		};
	/// @}

	/** @name Properties */ /// @{
		/** Type mask. */
		VarMask mask;

		/** Flags. */
		StateStore<Flags> flags;

		/**
			Check if Flags::optional is enabled.
		*/
		bool
		optional() const noexcept {
			return flags.test(Flags::optional);
		}
	/// @}

	/** @name Constructors and destructor */ /// @{
		/** Destructor. */
		~Field() = default;
		/** Copy constructor. */
		Field(Field const&) = default;
		/** Move constructor. */
		Field(Field&&) = default;

		/**
			Construct with flags.

			@note Mask is VarMask::none.

			@param flags %Flags.
		*/
		Field(
			Flags const flags = Flags::none
		) noexcept
			: mask(VarMask::none)
			, flags(flags)
		{}

		/**
			Construct with type and flags.

			@param type Single-type mask.
			@param flags %Flags.
		*/
		Field(
			VarType const type,
			Flags const flags = Flags::none
		) noexcept
			: mask(var_mask(type))
			, flags(flags)
		{}

		/**
			Construct with mask and flags.

			@param mask Mask.
			@param flags %Flags.
		*/
		Field(
			VarMask const mask,
			Flags const flags = Flags::none
		) noexcept
			: mask(mask)
			, flags(flags)
		{}
	/// @}

	/** @name Operators */ /// @{
		/** Copy assignment operator. */
		Field& operator=(Field const&) = default;
		/** Move assignment operator. */
		Field& operator=(Field&&) = default;
	/// @}
	};

	/** Identity vector type. */
	using identity_vector_type = duct::aux::vector<u8string>;
	/** Layout vector type. */
	using layout_vector_type = duct::aux::vector<Field>;
/// @}

protected:
	/**
		%Flags.
	*/
	enum class Flags {
		/**
			Whether to permit empty collections in layout validation.

			@note This is enabled by default.
		*/
		permit_empty = 1 << 0
	};

	/** %Flags. */
	StateStore<Flags> m_flags{Flags::permit_empty};
	/** Type mask. */
	VarMask m_type_mask{VarMask::none};
	/** Identity. */
	identity_vector_type m_identity{};
	/** Layout. */
	layout_vector_type m_layout{};

public:
/** @name Constructors and destructor */ /// @{
	/**
		Construct with @c VarMask::none type mask, empty identity,
		and empty layout.
	*/
	VarTemplate() = default;

	/**
		Construct with type mask, empty identity, and empty layout.

		@param type_mask Type mask.
	*/
	explicit
	VarTemplate(
		VarMask const type_mask
	)
		: m_type_mask(type_mask)
	{}

	/**
		Construct with type mask, identity, and empty layout.

		@param type_mask Type mask.
		@param identity Identity.
	*/
	VarTemplate(
		VarMask const type_mask,
		identity_vector_type identity
	)
		: m_type_mask(type_mask)
		, m_identity(std::move(identity))
	{}

	/**
		Construct with type mask, layout, and empty identity.

		@param type_mask Type mask.
		@param layout Layout.
	*/
	VarTemplate(
		VarMask const type_mask,
		layout_vector_type layout
	)
		: m_type_mask(type_mask)
		, m_layout(std::move(layout))
	{}

	/**
		Construct with type mask, identity, and layout.

		@param type_mask Type mask.
		@param identity Identity.
		@param layout Layout.
	*/
	VarTemplate(
		VarMask const type_mask,
		identity_vector_type identity,
		layout_vector_type layout
	)
		: m_type_mask(type_mask)
		, m_identity(std::move(identity))
		, m_layout(std::move(layout))
	{}

	/** Copy constructor. */
	VarTemplate(VarTemplate const&) = default;
	/** Move constructor. */
	VarTemplate(VarTemplate&&) = default;
	/** Destructor. */
	virtual ~VarTemplate() = default;
/// @}

/** @name Operators */ /// @{
	/** Copy assignment operator. */
	VarTemplate& operator=(VarTemplate const&) = default;
	/** Move assignment operator. */
	VarTemplate& operator=(VarTemplate&&) = default;
/// @}

/** @name Properties */ /// @{
	/**
		Enable or disable flags.

		@param flags %Flags.
		@param enable Whether to enable or disable the flags.
	*/
	void
	set_flags(
		Flags const flags,
		bool const enable
	) noexcept {
		m_flags.set(flags, enable);
	}

	/**
		Check if Flags::permit_empty is enabled.
	*/
	bool
	permit_empty() const noexcept {
		return m_flags.test(Flags::permit_empty);
	}

	/**
		Set type mask.

		@param type_mask New type mask.
		@sa validate_type(Var const&) const
	*/
	void
	set_type_mask(
		VarMask const type_mask
	) noexcept {
		m_type_mask = type_mask;
	}

	/**
		Set type mask (single type).

		@param type New type mask.
		@sa validate_type(Var const&) const
	*/
	void
	set_type_mask(
		VarType const type
	) noexcept {
		m_type_mask = var_mask(type);
	}

	/**
		Get type mask.

		@returns The current type mask.
		@sa validate_type(Var const&) const
	*/
	VarMask
	get_type_mask() const noexcept {
		return m_type_mask;
	}

	/**
		Set identity.

		@param identity New identity.
		@sa validate_identity(Var const&) const
	*/
	void
	set_identity(
		identity_vector_type identity
	) {
		m_identity = std::move(identity);
	}

	/**
		Get identity.

		@returns The current identity.
		@sa validate_identity(Var const&) const
	*/
	identity_vector_type&
	get_identity() noexcept {
		return m_identity;
	}

	/** @copydoc get_identity() */
	identity_vector_type const&
	get_identity() const noexcept {
		return m_identity;
	}

	/**
		Set layout.

		@param layout New layout.
		@sa validate_layout(Var const&) const
	*/
	void
	set_layout(
		layout_vector_type layout
	) {
		m_layout = std::move(layout);
	}

	/**
		Get layout.

		@returns The current layout.
		@sa validate_layout(Var const&) const
	*/
	layout_vector_type&
	get_layout() noexcept {
		return m_layout;
	}

	/** @copydoc get_layout() */
	layout_vector_type const&
	get_layout() const noexcept {
		return m_layout;
	}

/// @}

/** @name Validation */ /// @{
	/**
		Validate a variable.

		@note If @c validate_type(var) is @c true, layout validation
		is only done if @a var is a collection.

		@returns @c true iff @a var matches template in type, identity,
		and layout.
		@param var Variable to validate.
		@sa validate_type(Var const&) const,
			validate_identity(Var const&) const,
			validate_layout(Var const&) const
	*/
	bool
	validate(
		Var const& var
	) const noexcept {
		return
			validate_type(var) &&
			validate_identity(var) &&
			(!var.is_type_of(VarMask::collection) || validate_layout(var))
		;
	}

	/**
		Validate a variable by type.

		@returns @c true iff bitwise-and of @a var type and template
		type mask is non-zero.
		@param var Variable to validate.
	*/
	virtual bool
	validate_type(
		Var const& var
	) const noexcept {
		return var_type_is_of(var.get_type(), m_type_mask);
	}

	/**
		Validate a variable by identity.

		@returns @c true iff:
		-# identity is empty (permits any name),
		-# variable name matches any name from identity
		   (including empty name).
		@param var Variable to validate.
	*/
	virtual bool
	validate_identity(
		Var const& var
	) const noexcept {
		if (m_identity.empty()) {
			// Any name is permitted with empty identity
			return true;
		} else {
			for (auto const& iname : get_identity()) {
				if (var.get_name() == iname) {
					// Variable name matches a name from identity
					return true;
				}
			}
			// Variable name does not match a name from identity
			return false;
		}
	}

	/**
		Validate a variable by layout.

		@note The @c Field::Flags::optional flag will cause all succeeding
		fields to be considered optional.
		@note The @c Field::Flags::empty flag is only considered when layout
		contains a single field.

		@returns
		- @c false iff:
			-# variable is not a @c VarMask::collection,
			-# variable has more children than layout;
		- @c true iff:
			-# layout is empty (permits any collection),
			-# layout contains a single field with flag
			   @c Field::Flags::empty and variable has no children,
			-# children sequentially match layout fields exactly,
			-# children sequentially match [0..var.size()] layout fields
			   if a field from [0..var.size()+1] is optional
			   (thus making all subsequent fields optional).
		@param var Variable to validate.
	*/
	virtual bool
	validate_layout(
		Var const& var
	) const noexcept {
		if (var.is_type_of(VarMask::collection)) {
			if (m_layout.empty()) {
				// Any collection is permitted with empty layout
				return permit_empty();
			} else if (var.size() > get_layout().size()) {
				// Collection cannot be larger than layout
				return false;
			} else {
				auto vc_iter = var.cbegin();
				auto lo_iter = get_layout().cbegin();
				bool optional_met = false;
				for (; var.cend() != vc_iter; ++vc_iter, ++lo_iter) {
					if (!vc_iter->is_type_of(lo_iter->mask)) {
						// Child type does not match field
						return false;
					} else if (!optional_met) {
						optional_met = lo_iter->optional();
					}
				}
				if (optional_met || get_layout().cend() == lo_iter) {
					// Collection sequentially matches layout fields
					// exactly or any trailing fields are optional
					return true;
				} else {
					// No optional field has been met, and there are
					// unchecked trailing field(s)
					if (lo_iter->optional()) {
						// First trailing field is optional (therefore
						// all following fields are optional)
						return true;
					} else {
						// First trailing field is not optional
						return false;
					}
				}
			}
		} else {
			// Variable is not a collection
			return false;
		}
	}
/// @}
};

/** @} */ // end of doc-group var

} // namespace duct

#endif // DUCT_VARTEMPLATE_HPP_
<|endoftext|>


<commit_before>#include "SuiteExternalRelations.h"
#include "SuiteCommon.h"
#include <string>
#include <windows.h>
#include <initguid.h>
#include <mstask.h>
#include <taskschd.h>
#include <lmcons.h>
#include "taskschd_hs.h"

#ifdef DEBUG
#include <iostream>
#endif

namespace SuiteExtRel {
	int Schedule10(bool &na);
	int Schedule20(bool &na, bool current_user);
}

int SuiteExtRel::Schedule(bool current_user)
{
	int ret;
	bool na;

	ret=Schedule20(na, current_user);
	if (na) {
		if (!current_user) {
			//In Task Scheduler 1.0 you can't run task for any logged on user by using BUILTIN\Users group as user like in 2.0
			ErrorMessage(L"Task Scheduler 1.0 doesn't support scheduling GUI apps for all users!");
			return ERR_SUITEEXTREL+3;
		} else if ((ret=Schedule10(na), na)) {
			ErrorMessage(L"Task Scheduler 1.0 not available!");
			return ERR_SUITEEXTREL+4;
		}
	}
	if (ret) ErrorMessage(L"Error scheduling SnK HotkeySuite!");

	return ret;
}

int SuiteExtRel::Schedule10(bool &na)
{
	int ret=ERR_SUITEEXTREL+1;
	na=false;

	CoInitialize(NULL);

	wchar_t uname[UNLEN+1];
	DWORD uname_len=UNLEN+1;
	GetUserName(uname, &uname_len);
	std::wstring tname(L"SnK HotkeySuite [");
	tname.append(uname);
	tname.append({L']'});

	ITaskScheduler *pITS;
	if (SUCCEEDED(CoCreateInstance(CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskScheduler, (void**)&pITS))) {
#ifdef DEBUG
		std::wcerr<<L"SCHEDULE: Task Scheduler 1.0 available"<<std::endl;
#endif
		ITask *pITask;
		if (SUCCEEDED(pITS->NewWorkItem(tname.c_str(), CLSID_CTask, IID_ITask, (IUnknown**)&pITask))) {
			ITaskTrigger *pITaskTrigger;
			WORD piNewTrigger;
			if (SUCCEEDED(pITask->SetApplicationName(GetExecutableFileName().c_str()))&&
				SUCCEEDED(pITask->SetWorkingDirectory(GetExecutableFileName(L"").c_str()))&&
				SUCCEEDED(pITask->SetMaxRunTime(INFINITE))&&
				SUCCEEDED(pITask->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON))&&		//TASK_FLAG_RUN_ONLY_IF_LOGGED_ON required if pwszPassword in SetAccountInformation is NULL
				SUCCEEDED(pITask->SetAccountInformation(uname, NULL))&&				//Required
				SUCCEEDED(pITask->CreateTrigger(&piNewTrigger, &pITaskTrigger))) {
				TASK_TRIGGER trigger={};
				trigger.wBeginDay=1;		//Required
				trigger.wBeginMonth=1;		//Required
				trigger.wBeginYear=1970;	//Required
				trigger.cbTriggerSize=sizeof(TASK_TRIGGER);
				trigger.TriggerType=TASK_EVENT_TRIGGER_AT_LOGON;

				if (SUCCEEDED(pITaskTrigger->SetTrigger(&trigger))) {
					IPersistFile *pIPersistFile;
					if (SUCCEEDED(pITask->QueryInterface(IID_PPV_ARGS(&pIPersistFile)))) {
						if (SUCCEEDED(pIPersistFile->Save(NULL, TRUE))) ret=0;
						pIPersistFile->Release();
					}
				}
				pITaskTrigger->Release();
			}
			pITask->Release();
		}
		pITS->Release();
	} else {
		na=true;
		ret=0;
	}

	CoUninitialize();

	return ret;
}

int SuiteExtRel::Schedule20(bool &na, bool current_user)
{
	int ret=ERR_SUITEEXTREL+2;
	na=false;

	CoInitialize(NULL);	//Same as CoInitializeEx(NULL, COINIT_APARTMENTTHREADED), whatever, we don't need COINIT_MULTITHREADED
	//CoInitializeSecurity(NULL,-1,NULL,NULL,RPC_C_AUTHN_LEVEL_PKT_PRIVACY,RPC_C_IMP_LEVEL_IMPERSONATE,NULL,0,NULL);

	std::wstring tname(L"SnK HotkeySuite");
	BSTR uname_bstr=NULL;
	if (current_user) {
		wchar_t uname[UNLEN+1];
		DWORD uname_len=UNLEN+1;
		GetUserName(uname, &uname_len);
		tname.append({L' ', L'['});
		tname.append(uname);
		tname.append({L']'});
	} else {
		uname_bstr=SysAllocString(L"Users");
	}

	ITaskService *pService;
	if (SUCCEEDED(CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService))) {
#ifdef DEBUG
		std::wcerr<<L"SCHEDULE: Task Scheduler 2.0 available"<<std::endl;
#endif
		ITaskDefinition *pTask;
		VARIANT empty_var={VT_EMPTY};
		if (SUCCEEDED(pService->Connect(empty_var, empty_var, empty_var, empty_var))&&
			SUCCEEDED(pService->NewTask(0, &pTask))) {
			IPrincipal *pPrincipal;
			if (SUCCEEDED(pTask->get_Principal(&pPrincipal))) {
				ITaskSettings *pTaskSettings;
				if (SUCCEEDED(pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST))&&
					(current_user?true:(uname_bstr&&SUCCEEDED(pPrincipal->put_GroupId(uname_bstr))))&&
					SUCCEEDED(pTask->get_Settings(&pTaskSettings))) {
					if (BSTR infinite_bstr=SysAllocString(L"PT0S")) {
						ITriggerCollection *pTriggerCollection;
						if (SUCCEEDED(pTaskSettings->put_ExecutionTimeLimit(infinite_bstr))&&
							SUCCEEDED(pTaskSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE))&&
							SUCCEEDED(pTaskSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE))&&
							SUCCEEDED(pTask->get_Triggers(&pTriggerCollection))) {
							ITrigger *pTrigger;
							if (SUCCEEDED(pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger))) {
								IActionCollection *pActionCollection;
								if (SUCCEEDED(pTask->get_Actions(&pActionCollection))) {
									IAction *pAction;
									if (SUCCEEDED(pActionCollection->Create(TASK_ACTION_EXEC, &pAction))) {
										IExecAction *pExecAction;
										if (SUCCEEDED(pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction))) {
											if (BSTR hspath_bstr=SysAllocString(GetExecutableFileName().c_str())) {
												if (BSTR hsdir_bstr=SysAllocString(GetExecutableFileName(L"").c_str())) {
													BSTR root_bstr;
													if (SUCCEEDED(pExecAction->put_Path(hspath_bstr))&&
														SUCCEEDED(pExecAction->put_WorkingDirectory(hsdir_bstr))&&
														(root_bstr=SysAllocString(L"\\"))) {
														ITaskFolder *pRootFolder;
														if (SUCCEEDED(pService->GetFolder(root_bstr, &pRootFolder))) {
															if (BSTR tname_bstr=SysAllocString(tname.c_str())) {
																IRegisteredTask *pRegisteredTask;
																if (SUCCEEDED(pRootFolder->RegisterTaskDefinition(tname_bstr, pTask, TASK_CREATE_OR_UPDATE, empty_var, empty_var, TASK_LOGON_INTERACTIVE_TOKEN, empty_var, &pRegisteredTask))) {
																	ret=0;
																	pRegisteredTask->Release();
																}
																SysFreeString(tname_bstr);
															}
															pRootFolder->Release();
														}
														SysFreeString(root_bstr);
													}
													SysFreeString(hsdir_bstr);
												}
												SysFreeString(hspath_bstr);
											}
											pExecAction->Release();
										}
										pAction->Release();
									}
									pActionCollection->Release();
								}
								pTrigger->Release();
							}
							pTriggerCollection->Release();
						}
						SysFreeString(infinite_bstr);
					}
					pTaskSettings->Release();
				}
				pPrincipal->Release();
			}
			pTask->Release();
		}
		pService->Release();
	} else {
		na=true;
		ret=0;
	}

	if (uname_bstr)
		SysFreeString(uname_bstr);

	CoUninitialize();

	return ret;
}<commit_msg>Scheduled tasks should be silently recreated if exist<commit_after>#include "SuiteExternalRelations.h"
#include "SuiteCommon.h"
#include <string>
#include <windows.h>
#include <initguid.h>
#include <mstask.h>
#include <taskschd.h>
#include <lmcons.h>
#include "taskschd_hs.h"

#ifdef DEBUG
#include <iostream>
#endif

namespace SuiteExtRel {
	int Schedule10(bool &na);
	int Schedule20(bool &na, bool current_user);
}

int SuiteExtRel::Schedule(bool current_user)
{
	int ret;
	bool na;

	ret=Schedule20(na, current_user);
	if (na) {
		if (!current_user) {
			//In Task Scheduler 1.0 you can't run task for any logged on user by using BUILTIN\Users group as user like in 2.0
			ErrorMessage(L"Task Scheduler 1.0 doesn't support scheduling GUI apps for all users!");
			return ERR_SUITEEXTREL+3;
		} else if ((ret=Schedule10(na), na)) {
			ErrorMessage(L"Task Scheduler 1.0 not available!");
			return ERR_SUITEEXTREL+4;
		}
	}
	if (ret) ErrorMessage(L"Error scheduling SnK HotkeySuite! Make sure that you have Admin rights before scheduling a task.");

	return ret;
}

int SuiteExtRel::Schedule10(bool &na)
{
	int ret=ERR_SUITEEXTREL+1;
	na=false;

	CoInitialize(NULL);

	wchar_t uname[UNLEN+1];
	DWORD uname_len=UNLEN+1;
	GetUserName(uname, &uname_len);
	std::wstring tname(L"SnK HotkeySuite [");
	tname.append(uname);
	tname.append({L']'});

	ITaskScheduler *pITS;
	if (SUCCEEDED(CoCreateInstance(CLSID_CTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskScheduler, (void**)&pITS))) {
#ifdef DEBUG
		std::wcerr<<L"SCHEDULE: Task Scheduler 1.0 available"<<std::endl;
#endif
		ITask *pITask;
		//ITask->Delete w/ ITask->NewWorkItem: if task exists - we are silently recreating it
		pITS->Delete(tname.c_str());
		if (SUCCEEDED(pITS->NewWorkItem(tname.c_str(), CLSID_CTask, IID_ITask, (IUnknown**)&pITask))) {
			ITaskTrigger *pITaskTrigger;
			WORD piNewTrigger;
			if (SUCCEEDED(pITask->SetApplicationName(GetExecutableFileName().c_str()))&&
				SUCCEEDED(pITask->SetWorkingDirectory(GetExecutableFileName(L"").c_str()))&&
				SUCCEEDED(pITask->SetMaxRunTime(INFINITE))&&
				SUCCEEDED(pITask->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON))&&		//TASK_FLAG_RUN_ONLY_IF_LOGGED_ON required if pwszPassword in SetAccountInformation is NULL
				SUCCEEDED(pITask->SetAccountInformation(uname, NULL))&&				//Required
				SUCCEEDED(pITask->CreateTrigger(&piNewTrigger, &pITaskTrigger))) {
				TASK_TRIGGER trigger={};
				trigger.wBeginDay=1;		//Required
				trigger.wBeginMonth=1;		//Required
				trigger.wBeginYear=1970;	//Required
				trigger.cbTriggerSize=sizeof(TASK_TRIGGER);
				trigger.TriggerType=TASK_EVENT_TRIGGER_AT_LOGON;

				if (SUCCEEDED(pITaskTrigger->SetTrigger(&trigger))) {
					IPersistFile *pIPersistFile;
					if (SUCCEEDED(pITask->QueryInterface(IID_PPV_ARGS(&pIPersistFile)))) {
						if (SUCCEEDED(pIPersistFile->Save(NULL, TRUE))) ret=0;
						pIPersistFile->Release();
					}
				}
				pITaskTrigger->Release();
			}
			pITask->Release();
		}
		pITS->Release();
	} else {
		na=true;
		ret=0;
	}

	CoUninitialize();

	return ret;
}

int SuiteExtRel::Schedule20(bool &na, bool current_user)
{
	int ret=ERR_SUITEEXTREL+2;
	na=false;

	CoInitialize(NULL);	//Same as CoInitializeEx(NULL, COINIT_APARTMENTTHREADED), whatever, we don't need COINIT_MULTITHREADED

	std::wstring tname(L"SnK HotkeySuite");
	BSTR uname_bstr=NULL;
	if (current_user) {
		wchar_t uname[UNLEN+1];
		DWORD uname_len=UNLEN+1;
		GetUserName(uname, &uname_len);
		tname.append({L' ', L'['});
		tname.append(uname);
		tname.append({L']'});
	} else {
		uname_bstr=SysAllocString(L"Users");
	}

	ITaskService *pService;
	if (SUCCEEDED(CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (void**)&pService))) {
#ifdef DEBUG
		std::wcerr<<L"SCHEDULE: Task Scheduler 2.0 available"<<std::endl;
#endif
		ITaskDefinition *pTask;
		VARIANT empty_var={VT_EMPTY};
		if (SUCCEEDED(pService->Connect(empty_var, empty_var, empty_var, empty_var))&&
			SUCCEEDED(pService->NewTask(0, &pTask))) {
			IPrincipal *pPrincipal;
			if (SUCCEEDED(pTask->get_Principal(&pPrincipal))) {
				ITaskSettings *pTaskSettings;
				if (SUCCEEDED(pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST))&&
					(current_user?true:(uname_bstr&&SUCCEEDED(pPrincipal->put_GroupId(uname_bstr))))&&
					SUCCEEDED(pTask->get_Settings(&pTaskSettings))) {
					if (BSTR infinite_bstr=SysAllocString(L"PT0S")) {
						ITriggerCollection *pTriggerCollection;
						if (SUCCEEDED(pTaskSettings->put_ExecutionTimeLimit(infinite_bstr))&&
							SUCCEEDED(pTaskSettings->put_StopIfGoingOnBatteries(VARIANT_FALSE))&&
							SUCCEEDED(pTaskSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE))&&
							SUCCEEDED(pTask->get_Triggers(&pTriggerCollection))) {
							ITrigger *pTrigger;
							if (SUCCEEDED(pTriggerCollection->Create(TASK_TRIGGER_LOGON, &pTrigger))) {
								IActionCollection *pActionCollection;
								if (SUCCEEDED(pTask->get_Actions(&pActionCollection))) {
									IAction *pAction;
									if (SUCCEEDED(pActionCollection->Create(TASK_ACTION_EXEC, &pAction))) {
										IExecAction *pExecAction;
										if (SUCCEEDED(pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction))) {
											if (BSTR hspath_bstr=SysAllocString(GetExecutableFileName().c_str())) {
												if (BSTR hsdir_bstr=SysAllocString(GetExecutableFileName(L"").c_str())) {
													BSTR root_bstr;
													if (SUCCEEDED(pExecAction->put_Path(hspath_bstr))&&
														SUCCEEDED(pExecAction->put_WorkingDirectory(hsdir_bstr))&&
														(root_bstr=SysAllocString(L"\\"))) {
														ITaskFolder *pRootFolder;
														if (SUCCEEDED(pService->GetFolder(root_bstr, &pRootFolder))) {
															if (BSTR tname_bstr=SysAllocString(tname.c_str())) {
																IRegisteredTask *pRegisteredTask;
																//ITaskService->NewTask w/ TASK_CREATE_OR_UPDATE: if task exists - we are silently recreating it
																if (SUCCEEDED(pRootFolder->RegisterTaskDefinition(tname_bstr, pTask, TASK_CREATE_OR_UPDATE, empty_var, empty_var, TASK_LOGON_INTERACTIVE_TOKEN, empty_var, &pRegisteredTask))) {
																	ret=0;
																	pRegisteredTask->Release();
																}
																SysFreeString(tname_bstr);
															}
															pRootFolder->Release();
														}
														SysFreeString(root_bstr);
													}
													SysFreeString(hsdir_bstr);
												}
												SysFreeString(hspath_bstr);
											}
											pExecAction->Release();
										}
										pAction->Release();
									}
									pActionCollection->Release();
								}
								pTrigger->Release();
							}
							pTriggerCollection->Release();
						}
						SysFreeString(infinite_bstr);
					}
					pTaskSettings->Release();
				}
				pPrincipal->Release();
			}
			pTask->Release();
		}
		pService->Release();
	} else {
		na=true;
		ret=0;
	}

	if (uname_bstr)
		SysFreeString(uname_bstr);

	CoUninitialize();

	return ret;
}<|endoftext|>