<commit_before>#include <map>
#include <string>

#include "lukki-db-application.h"
#include "vtrc-common/vtrc-thread-pool.h"
#include "vtrc-common/vtrc-rpc-service-wrapper.h"
#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-closure-holder.h"

#include "vtrc-common/vtrc-rpc-channel.h"

#include "vtrc-server/vtrc-channels.h"

#include "protocol/lukkidb.pb.h"

#include "google/protobuf/descriptor.h"

#include "vtrc-bind.h"
#include "vtrc-ref.h"

#include "boost/asio.hpp"

namespace lukki_db {

    using namespace vtrc;

    namespace {

        typedef std::map<std::string, vtrc_example::lukki_string_list> db_type;

        class lukki_db_impl: public vtrc_example::lukki_db {

            typedef lukki_db_impl this_type;

            application              &app_;
            common::connection_iface *connection_;

        public:

            lukki_db_impl( application &app, common::connection_iface *c)
                :app_(app)
                ,connection_(c)
            { }

        private:

            static void yks_closure( bool success, const std::string &mess,
                              ::google::protobuf::RpcController* controller,
                              vtrc::shared_ptr<common::closure_holder> holder)
            {
                if( !success ) {
                    controller->SetFailed( mess );
                }
            }

            void init(::google::protobuf::RpcController* /*controller*/,
                         const ::vtrc_example::empty* /*request*/,
                         ::vtrc_example::empty* /*response*/,
                         ::google::protobuf::Closure* done)
            {
                done->Run( );
            }

            void set(::google::protobuf::RpcController* controller,
                         const ::vtrc_example::value_set_req* request,
                         ::vtrc_example::empty* response,
                         ::google::protobuf::Closure* done)
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );
                app_.set( request->name( ), request->value( ),
                          vtrc::bind( &this_type::yks_closure,
                                      _1, _2, controller, holder) );
            }

            void upd(::google::protobuf::RpcController* controller,
                            const ::vtrc_example::value_set_req* request,
                            ::vtrc_example::empty* response,
                            ::google::protobuf::Closure* done)
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );
                app_.upd( request->name( ), request->value( ),
                          vtrc::bind( &this_type::yks_closure,
                                      _1, _2, controller, holder) );
            }

            void del(::google::protobuf::RpcController* controller,
                         const ::vtrc_example::name_req* request,
                         ::vtrc_example::empty* response,
                         ::google::protobuf::Closure* done)
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );

                app_.del( request->name( ),
                          vtrc::bind( &this_type::yks_closure,
                                      _1, _2, controller, holder) );

            }

            template <typename ResType>
            static void mess_closure( bool success, const std::string &mess,
                     vtrc::shared_ptr<ResType> res, ResType* response,
                     ::google::protobuf::RpcController* controller,
                     vtrc::shared_ptr<common::closure_holder> holder )
            {
                if( !success ) {
                    controller->SetFailed( mess );
                } else {
                    response->Swap( res.get( ) );
                }
            }

            void get(::google::protobuf::RpcController* controller,
                         const ::vtrc_example::name_req* request,
                         ::vtrc_example::lukki_string_list* response,
                         ::google::protobuf::Closure* done)
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );

                typedef vtrc_example::lukki_string_list res_type;

                vtrc::shared_ptr<res_type> res(new res_type);

                app_.get( request->name( ), res,
                           vtrc::bind( &this_type::mess_closure<res_type>,
                                  _1, _2,
                                  res, response, controller, holder) );
            }

            void stat(::google::protobuf::RpcController* controller,
                         const ::vtrc_example::empty* request,
                         ::vtrc_example::db_stat* response,
                         ::google::protobuf::Closure* done)
            {

                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );

                typedef vtrc_example::db_stat res_type;

                vtrc::shared_ptr<res_type> res(new res_type);
                app_.stat( res, vtrc::bind( &this_type::mess_closure<res_type>,
                                         _1, _2,
                                         res, response, controller, holder) );
            }

            void exist(::google::protobuf::RpcController* controller,
                     const ::vtrc_example::name_req* request,
                     ::vtrc_example::exist_res* response,
                     ::google::protobuf::Closure* done )
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );

                typedef vtrc_example::exist_res res_type;
                vtrc::shared_ptr<res_type> res (new res_type);
                app_.exist( request->name( ), res,
                            vtrc::bind( &this_type::mess_closure<res_type>,
                                        _1, _2,
                                        res, response, controller, holder ));

            }
            void subscribe(::google::protobuf::RpcController* controller,
                     const ::vtrc_example::empty* request,
                     ::vtrc_example::empty* response,
                     ::google::protobuf::Closure* done)
            {
                common::closure_holder holder(done);
                app_.subscribe_client( connection_ );
            }
        };
    }

    struct  application::impl {

        enum { RECORD_DELETED, RECORD_ADDED, RECORD_CHANGED };

        common::thread_pool             db_thread_;
        db_type                         db_;
        vtrc_example::db_stat           db_stat_;
        boost::asio::io_service::strand event_queue_;

        std::vector<server::listener_sptr>  listeners_;

        typedef vtrc::shared_ptr<common::rpc_channel> channel_sptr;
        typedef std::pair<
            common::connection_iface_wptr, channel_sptr
        > connection_channel_pair;

        typedef std::list<connection_channel_pair> subscriber_list_type;

        subscriber_list_type subscribers_;

        impl( boost::asio::io_service &rpc_service )
            :db_thread_(1)
            ,event_queue_(rpc_service)
        { }

        void on_new_connection( server::listener_sptr l,
                                const common::connection_iface *c )
        {
            std::cout << "New connection: "
                      << "\n\tep:     " << l->name( )
                      << "\n\tclient: " << c->name( )
                      << "\n"
                        ;
        }

        void on_stop_connection( server::listener_sptr l,
                                 const common::connection_iface *c )
        {
            std::cout << "Close connection: "
                      << c->name( ) << "\n";
        }

        void set( const std::string &name,
                  const vtrc_example::lukki_string_list &value,
                  const operation_closure &closure)
        {
            if( db_.find( name ) != db_.end( ) ) {
                if( closure ) closure( false, "Record already exists" );
            } else {
                db_stat_.set_set_requests( db_stat_.set_requests( ) + 1 );
                db_[name] = value;
                db_stat_.set_total_records( db_.size( ) );
                send_event( name , RECORD_ADDED );
                if( closure ) closure( true, "Success" );
            }
        }

        void upd( const std::string &name,
                  const vtrc_example::lukki_string_list &value,
                  const operation_closure &closure)
        {
            db_stat_.set_upd_requests( db_stat_.upd_requests( ) + 1 );
            db_type::iterator f( db_.find( name ));

            if( f == db_.end( ) ) {
                if( closure ) closure( false, "Record was not found" );
            } else {
                f->second.CopyFrom( value );
                send_event( name , RECORD_CHANGED );
                if( closure ) closure( true, "Success" );
            }
        }

        void get( const std::string &name,
                  vtrc::shared_ptr<vtrc_example::lukki_string_list> value,
                  const operation_closure &closure)
        {
            db_stat_.set_get_requests( db_stat_.get_requests( ) + 1 );
            db_type::const_iterator f( db_.find( name ));
            if( f == db_.end( ) ) {
                if( closure ) closure( false, "Record was not found" );
            } else {
                value->CopyFrom( f->second );
                if( closure ) closure( true, "Success" );
            }
        }

        void del( const std::string &name,
                  const operation_closure &closure)
        {
            db_stat_.set_del_requests( db_stat_.del_requests( ) + 1 );
            db_type::iterator f( db_.find( name ));
            if( f == db_.end( ) ) {
                if( closure ) closure( false, "Record was not found" );
            } else {
                db_.erase( f );
                send_event( name , RECORD_DELETED );
                if( closure ) closure( true, "Success" );
            }
        }

        void stat( vtrc::shared_ptr<vtrc_example::db_stat> stat,
                   const operation_closure &closure)
        {
            stat->CopyFrom( db_stat_ );
            if( closure ) closure( true, "Success" );
        }

        void exist( const std::string &name,
                    vtrc::shared_ptr<vtrc_example::exist_res> res,
                    const operation_closure &closure)
        {
            res->set_value( db_.find( name ) != db_.end( ) );
            if( closure ) closure( true, "Success" );
        }

        /// events
        void send_event( const std::string &record, unsigned changed )
        {
            event_queue_.post( vtrc::bind( &impl::send_event_impl, this,
                                           record, changed ) );
        }

        void send_event( vtrc::shared_ptr<common::rpc_channel> channel,
                         const std::string &record, unsigned changed)
        {
            try {

                vtrc_example::lukki_events_Stub s(channel.get( ));
                vtrc_example::name_req req;

                req.set_name( record );
                switch (changed) {
                case RECORD_DELETED:
                    s.value_removed( NULL, &req, NULL, NULL );
                    break;
                case RECORD_CHANGED:
                    s.value_changed( NULL, &req, NULL, NULL );
                    break;
                case RECORD_ADDED:
                    s.new_value( NULL, &req, NULL, NULL );
                    break;
                default:
                    break;
                }
            } catch( ... ) {
                ;;;
            }
        }

        void send_event_impl( const std::string &record, unsigned changed )
        {
            subscriber_list_type::iterator b(subscribers_.begin( ));
            while( b != subscribers_.end( ) ) {
                common::connection_iface_sptr lck(b->first.lock( ));
                if( lck ) {
                    send_event( b->second, record, changed );
                    ++b;
                } else {
                    b = subscribers_.erase( b );
                }
            }
        }

        void send_subscribed( common::rpc_channel &channel )
        {
            try {
                vtrc_example::lukki_events_Stub s(&channel);
                vtrc_example::empty r;
                s.subscribed( NULL, &r, &r, NULL );
            } catch( ... ) {
                ;;;
            }
        }

        void subscribe_impl( common::connection_iface_wptr conn )
        {
            common::connection_iface_sptr lck(conn.lock( ));
            if( lck ) {
                vtrc::shared_ptr<common::rpc_channel> channel
                    (server::channels::unicast::create_event_channel
                            ( lck, true ));
                subscribers_.push_back( std::make_pair(conn, channel) );
                send_subscribed( *channel );
            }
        }

        void subscribe_client( vtrc::common::connection_iface* conn )
        {
            event_queue_.post( vtrc::bind(&impl::subscribe_impl, this,
                               conn->weak_from_this( ) ));
        }

    };

    application::application( vtrc::common::pool_pair &pp )
        :vtrc::server::application(pp)
        ,impl_(new impl(pp.get_rpc_service( )))
    {

    }

    application::~application( )
    {
        delete impl_;
    }

    vtrc::shared_ptr<common::rpc_service_wrapper>
         application::get_service_by_name( vtrc::common::connection_iface* conn,
                                  const std::string &service_name )
    {
        if( service_name == lukki_db_impl::descriptor( )->full_name( ) ) {
            return vtrc::make_shared<common::rpc_service_wrapper>
                                        ( new lukki_db_impl( *this, conn ) );
        }
        return vtrc::shared_ptr<common::rpc_service_wrapper>( );
    }

    void application::attach_start_listener( server::listener_sptr listen )
    {
        listen->get_on_new_connection( ).connect(
                    vtrc::bind( &impl::on_new_connection, impl_, listen, _1 ));

        listen->get_on_stop_connection( ).connect(
                    vtrc::bind( &impl::on_stop_connection, impl_, listen, _1 ));

        listen->start( );
        impl_->listeners_.push_back( listen );
    }

    void application::set( const std::string &name,
              const vtrc_example::lukki_string_list &value,
              const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
                    vtrc::bind( &impl::set, impl_,name, value, closure));
    }

    void application::upd( const std::string &name,
              const vtrc_example::lukki_string_list &value,
              const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
                    vtrc::bind( &impl::upd, impl_,name, value, closure));
    }

    void application::get( const std::string &name,
                       vtrc::shared_ptr<vtrc_example::lukki_string_list> value,
                       const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
                    vtrc::bind( &impl::get, impl_, name,
                                value, closure));
    }

    void application::del( const std::string &name,
                           const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
                    vtrc::bind( &impl::del, impl_, name, closure));
    }

    void application::stat(vtrc::shared_ptr<vtrc_example::db_stat> stat,
                            const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
               vtrc::bind( &impl::stat, impl_, stat, closure));
    }

    void application::exist( const std::string &name,
                vtrc::shared_ptr<vtrc_example::exist_res> res,
                const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
               vtrc::bind( &impl::exist, impl_, name, res, closure));
    }

    void application::subscribe_client( vtrc::common::connection_iface* conn )
    {
        impl_->subscribe_client( conn );
    }

}

<commit_msg>examples<commit_after>#include <map>
#include <string>

#include "lukki-db-application.h"
#include "vtrc-common/vtrc-thread-pool.h"
#include "vtrc-common/vtrc-rpc-service-wrapper.h"
#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-closure-holder.h"

#include "vtrc-common/vtrc-rpc-channel.h"

#include "vtrc-server/vtrc-channels.h"

#include "protocol/lukkidb.pb.h"

#include "google/protobuf/descriptor.h"

#include "vtrc-bind.h"
#include "vtrc-ref.h"

#include "boost/asio.hpp"

namespace lukki_db {

    using namespace vtrc;

    namespace {

        typedef std::map<std::string, vtrc_example::lukki_string_list> db_type;

        class lukki_db_impl: public vtrc_example::lukki_db {

            typedef lukki_db_impl this_type;

            application              &app_;
            common::connection_iface *connection_;

        public:

            lukki_db_impl( application &app, common::connection_iface *c)
                :app_(app)
                ,connection_(c)
            { }

        private:

            static void yks_closure( bool success, const std::string &mess,
                              ::google::protobuf::RpcController* controller,
                              vtrc::shared_ptr<common::closure_holder> holder)
            {
                if( !success ) {
                    controller->SetFailed( mess );
                }
            }

            void init(::google::protobuf::RpcController* /*controller*/,
                         const ::vtrc_example::empty* /*request*/,
                         ::vtrc_example::empty* /*response*/,
                         ::google::protobuf::Closure* done)
            {
                done->Run( );
            }

            void set(::google::protobuf::RpcController* controller,
                         const ::vtrc_example::value_set_req* request,
                         ::vtrc_example::empty* response,
                         ::google::protobuf::Closure* done)
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );
                app_.set( request->name( ), request->value( ),
                          vtrc::bind( &this_type::yks_closure,
                                      _1, _2, controller, holder) );
            }

            void upd(::google::protobuf::RpcController* controller,
                            const ::vtrc_example::value_set_req* request,
                            ::vtrc_example::empty* response,
                            ::google::protobuf::Closure* done)
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );
                app_.upd( request->name( ), request->value( ),
                          vtrc::bind( &this_type::yks_closure,
                                      _1, _2, controller, holder) );
            }

            void del(::google::protobuf::RpcController* controller,
                         const ::vtrc_example::name_req* request,
                         ::vtrc_example::empty* response,
                         ::google::protobuf::Closure* done)
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );

                app_.del( request->name( ),
                          vtrc::bind( &this_type::yks_closure,
                                      _1, _2, controller, holder) );

            }

            template <typename ResType>
            static void mess_closure( bool success, const std::string &mess,
                     vtrc::shared_ptr<ResType> res, ResType* response,
                     ::google::protobuf::RpcController* controller,
                     vtrc::shared_ptr<common::closure_holder> holder )
            {
                if( !success ) {
                    controller->SetFailed( mess );
                } else {
                    response->Swap( res.get( ) );
                }
            }

            void get(::google::protobuf::RpcController* controller,
                         const ::vtrc_example::name_req* request,
                         ::vtrc_example::lukki_string_list* response,
                         ::google::protobuf::Closure* done)
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );

                typedef vtrc_example::lukki_string_list res_type;

                vtrc::shared_ptr<res_type> res(new res_type);

                app_.get( request->name( ), res,
                           vtrc::bind( &this_type::mess_closure<res_type>,
                                  _1, _2,
                                  res, response, controller, holder) );
            }

            void stat(::google::protobuf::RpcController* controller,
                         const ::vtrc_example::empty* request,
                         ::vtrc_example::db_stat* response,
                         ::google::protobuf::Closure* done)
            {

                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );

                typedef vtrc_example::db_stat res_type;

                vtrc::shared_ptr<res_type> res(new res_type);
                app_.stat( res, vtrc::bind( &this_type::mess_closure<res_type>,
                                         _1, _2,
                                         res, response, controller, holder) );
            }

            void exist(::google::protobuf::RpcController* controller,
                     const ::vtrc_example::name_req* request,
                     ::vtrc_example::exist_res* response,
                     ::google::protobuf::Closure* done )
            {
                vtrc::shared_ptr<common::closure_holder> holder(
                            common::closure_holder::create(done) );

                typedef vtrc_example::exist_res res_type;
                vtrc::shared_ptr<res_type> res (new res_type);
                app_.exist( request->name( ), res,
                            vtrc::bind( &this_type::mess_closure<res_type>,
                                        _1, _2,
                                        res, response, controller, holder ));

            }
            void subscribe(::google::protobuf::RpcController* controller,
                     const ::vtrc_example::empty* request,
                     ::vtrc_example::empty* response,
                     ::google::protobuf::Closure* done)
            {
                common::closure_holder holder(done);
                app_.subscribe_client( connection_ );
            }
        };
    }

    struct  application::impl {

        enum { RECORD_DELETED, RECORD_ADDED, RECORD_CHANGED };

        common::thread_pool             db_thread_;
        db_type                         db_;
        vtrc_example::db_stat           db_stat_;
        boost::asio::io_service::strand event_queue_;

        std::vector<server::listener_sptr>  listeners_;

        typedef vtrc::shared_ptr<common::rpc_channel> channel_sptr;
        typedef std::pair<
            common::connection_iface_wptr, channel_sptr
        > connection_channel_pair;

        typedef std::list<connection_channel_pair> subscriber_list_type;

        subscriber_list_type subscribers_;

        impl( boost::asio::io_service &rpc_service )
            :db_thread_(1)
            ,event_queue_(rpc_service)
        { }

        void on_new_connection( server::listener_sptr l,
                                const common::connection_iface *c )
        {
            std::cout << "New connection: "
                      << "\n\tep:     " << l->name( )
                      << "\n\tclient: " << c->name( )
                      << "\n"
                        ;
        }

        void on_stop_connection( server::listener_sptr l,
                                 const common::connection_iface *c )
        {
            std::cout << "Close connection: "
                      << c->name( ) << "\n";
        }

        void set( const std::string &name,
                  const vtrc_example::lukki_string_list &value,
                  const operation_closure &closure)
        {
            if( db_.find( name ) != db_.end( ) ) {
                if( closure ) closure( false, "Record already exists" );
            } else {
                db_stat_.set_set_requests( db_stat_.set_requests( ) + 1 );
                db_[name] = value;
                db_stat_.set_total_records( db_.size( ) );
                send_event( name , RECORD_ADDED );
                if( closure ) closure( true, "Success" );
            }
        }

        void upd( const std::string &name,
                  const vtrc_example::lukki_string_list &value,
                  const operation_closure &closure)
        {
            db_stat_.set_upd_requests( db_stat_.upd_requests( ) + 1 );
            db_type::iterator f( db_.find( name ));

            if( f == db_.end( ) ) {
                if( closure ) closure( false, "Record was not found" );
            } else {
                f->second.CopyFrom( value );
                send_event( name , RECORD_CHANGED );
                if( closure ) closure( true, "Success" );
            }
        }

        void get( const std::string &name,
                  vtrc::shared_ptr<vtrc_example::lukki_string_list> value,
                  const operation_closure &closure)
        {
            db_stat_.set_get_requests( db_stat_.get_requests( ) + 1 );
            db_type::const_iterator f( db_.find( name ));
            if( f == db_.end( ) ) {
                if( closure ) closure( false, "Record was not found" );
            } else {
                value->CopyFrom( f->second );
                if( closure ) closure( true, "Success" );
            }
        }

        void del( const std::string &name,
                  const operation_closure &closure)
        {
            db_stat_.set_del_requests( db_stat_.del_requests( ) + 1 );
            db_type::iterator f( db_.find( name ));
            if( f == db_.end( ) ) {
                if( closure ) closure( false, "Record was not found" );
            } else {
                db_.erase( f );
                send_event( name , RECORD_DELETED );
                if( closure ) closure( true, "Success" );
            }
        }

        void stat( vtrc::shared_ptr<vtrc_example::db_stat> stat,
                   const operation_closure &closure)
        {
            stat->CopyFrom( db_stat_ );
            if( closure ) closure( true, "Success" );
        }

        void exist( const std::string &name,
                    vtrc::shared_ptr<vtrc_example::exist_res> res,
                    const operation_closure &closure)
        {
            res->set_value( db_.find( name ) != db_.end( ) );
            if( closure ) closure( true, "Success" );
        }

        /// events
        void send_event( const std::string &record, unsigned changed )
        {
            event_queue_.post( vtrc::bind( &impl::send_event_impl, this,
                                           record, changed ) );
        }

        void send_event( vtrc::shared_ptr<common::rpc_channel> channel,
                         const std::string &record, unsigned changed)
        {
            try {

                vtrc_example::lukki_events_Stub s(channel.get( ));
                vtrc_example::name_req req;

                req.set_name( record );
                switch (changed) {
                case RECORD_DELETED:
                    s.value_removed( NULL, &req, NULL, NULL );
                    break;
                case RECORD_CHANGED:
                    s.value_changed( NULL, &req, NULL, NULL );
                    break;
                case RECORD_ADDED:
                    s.new_value( NULL, &req, NULL, NULL );
                    break;
                default:
                    break;
                }
            } catch( ... ) {
                ;;;
            }
        }

        void send_event_impl( const std::string &record, unsigned changed )
        {
            subscriber_list_type::iterator b(subscribers_.begin( ));
            while( b != subscribers_.end( ) ) {
                common::connection_iface_sptr lck(b->first.lock( ));
                if( lck ) {
                    send_event( b->second, record, changed );
                    ++b;
                } else {
                    b = subscribers_.erase( b );
                }
            }
        }

        void send_subscribed( common::rpc_channel &channel )
        {
            try {
                vtrc_example::lukki_events_Stub s(&channel);
                vtrc_example::empty r;
                s.subscribed( NULL, &r, &r, NULL );
            } catch( ... ) {
                ;;;
            }
        }

        void subscribe_impl( common::connection_iface_wptr conn )
        {
            common::connection_iface_sptr lck(conn.lock( ));
            if( lck ) {
                vtrc::shared_ptr<common::rpc_channel> channel
                    (server::channels::unicast::create_event_channel
                            ( lck, true ));
                subscribers_.push_back( std::make_pair(conn, channel) );
                send_subscribed( *channel );
            }
        }

        void subscribe_client( vtrc::common::connection_iface* conn )
        {
            event_queue_.post( vtrc::bind(&impl::subscribe_impl, this,
                               conn->weak_from_this( ) ));
        }

    };

    application::application( vtrc::common::pool_pair &pp )
        :vtrc::server::application(pp)
        ,impl_(new impl(pp.get_rpc_service( )))
    {

    }

    application::~application( )
    {
        delete impl_;
    }

    vtrc::shared_ptr<common::rpc_service_wrapper>
         application::get_service_by_name( vtrc::common::connection_iface* conn,
                                  const std::string &service_name )
    {
        if( service_name == lukki_db_impl::descriptor( )->full_name( ) ) {
            return vtrc::make_shared<common::rpc_service_wrapper>
                                        ( new lukki_db_impl( *this, conn ) );
        }
        return vtrc::shared_ptr<common::rpc_service_wrapper>( );
    }

    void application::attach_start_listener( server::listener_sptr listen )
    {
        listen->get_on_new_connection( ).connect(
                    vtrc::bind( &impl::on_new_connection, impl_, listen, _1 ));

        listen->get_on_stop_connection( ).connect(
                    vtrc::bind( &impl::on_stop_connection, impl_, listen, _1 ));

        listen->start( );
        impl_->listeners_.push_back( listen );
    }

    void application::set( const std::string &name,
              const vtrc_example::lukki_string_list &value,
              const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
                    vtrc::bind( &impl::set, impl_,name, value, closure));
    }

    void application::upd( const std::string &name,
              const vtrc_example::lukki_string_list &value,
              const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
                    vtrc::bind( &impl::upd, impl_,name, value, closure));
    }

    void application::get( const std::string &name,
                       vtrc::shared_ptr<vtrc_example::lukki_string_list> value,
                       const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
                    vtrc::bind( &impl::get, impl_, name, value, closure));
    }

    void application::del( const std::string &name,
                           const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
                    vtrc::bind( &impl::del, impl_, name, closure));
    }

    void application::stat(vtrc::shared_ptr<vtrc_example::db_stat> stat,
                            const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
               vtrc::bind( &impl::stat, impl_, stat, closure));
    }

    void application::exist( const std::string &name,
                vtrc::shared_ptr<vtrc_example::exist_res> res,
                const operation_closure &closure)
    {
        impl_->db_thread_.get_io_service( ).post(
               vtrc::bind( &impl::exist, impl_, name, res, closure));
    }

    void application::subscribe_client( vtrc::common::connection_iface* conn )
    {
        impl_->subscribe_client( conn );
    }

}

<|endoftext|>


<commit_before>/*******************************************************************************
 * c7a/data/data_manager.hpp
 *
 ******************************************************************************/

#ifndef C7A_DATA_DATA_MANAGER_HEADER
#define C7A_DATA_DATA_MANAGER_HEADER

#include <map>
#include <functional>
#include <stdexcept>
#include <memory> //unique_ptr
#include "block_iterator.hpp"
#include "../common/logger.hpp"

namespace c7a {
namespace data {

//! Identification for DIAs
typedef int DIAId;

//! function Signature for an emitt function
template<typename T>
using BlockEmitter = std::function<void(T)>;

//! Stores in-memory data
//!
//! Future versions: Provide access to remote DIAs
class DataManager
{
public:

    DataManager() : nextId_(0) { }

    DataManager(const DataManager&) = delete;
    DataManager & operator=(const DataManager&) = delete;

    //! returns iterator on requested partition
    //!
    //! \param id ID of the DIA
    template<class T>
    BlockIterator<T> GetLocalBlocks(DIAId id) {
        if (!Contains(id)) {
            throw std::runtime_error("target dia id unknown.");
        }
        return BlockIterator<T>(data_[id]);
    }

    //! returns true if the manager holds data of given DIA
    //!
    //! \param id ID of the DIA
    bool Contains(DIAId id) {
        //return data_.find(id) != data_.end();
        return data_.size() > id && id >= 0;
    }

    DIAId AllocateDIA() {
        SpacingLogger(true) << "Allocate DIA" << nextId_;
        //data_[nextId_] = std::unique_ptr<std::vector<Blob>>( new std::vector<Blob>() );
        data_.push_back( std::vector<Blob>() );
        return data_.size() - 1;
        //return nextId_++;
    }

    template<class T>
    BlockEmitter<T> GetLocalEmitter(DIAId id) {
        if (!Contains(id)) {
            throw std::runtime_error("target dia id unknown.");
        }
        auto& target = data_[id]; //yes. const ref to an unique_ptr
        return [& target](T elem){ target.push_back(Serialize(elem)); };
    }

private:
    DIAId nextId_;

    //YES I COULD just use a map of (int, vector) BUT then I have a weird
    //behaviour of std::map on inserts. Sometimes it randomly kills itself.
    //May depend on the compiler. Google it.
    //std::map<DIAId, std::unique_ptr<std::vector<Blob>>> data_;
    std::vector<std::vector<Blob>> data_;
};

}
}

#endif // !C7A_DATA_DATA_MANAGER_HEADER

/******************************************************************************/
<commit_msg>fix data manager allocate dia logger<commit_after>/*******************************************************************************
 * c7a/data/data_manager.hpp
 *
 ******************************************************************************/

#ifndef C7A_DATA_DATA_MANAGER_HEADER
#define C7A_DATA_DATA_MANAGER_HEADER

#include <map>
#include <functional>
#include <stdexcept>
#include <memory> //unique_ptr
#include "block_iterator.hpp"
#include "../common/logger.hpp"

namespace c7a {
namespace data {

//! Identification for DIAs
typedef int DIAId;

//! function Signature for an emitt function
template<typename T>
using BlockEmitter = std::function<void(T)>;

//! Stores in-memory data
//!
//! Future versions: Provide access to remote DIAs
class DataManager
{
public:

    DataManager() : nextId_(0) { }

    DataManager(const DataManager&) = delete;
    DataManager & operator=(const DataManager&) = delete;

    //! returns iterator on requested partition
    //!
    //! \param id ID of the DIA
    template<class T>
    BlockIterator<T> GetLocalBlocks(DIAId id) {
        if (!Contains(id)) {
            throw std::runtime_error("target dia id unknown.");
        }
        return BlockIterator<T>(data_[id]);
    }

    //! returns true if the manager holds data of given DIA
    //!
    //! \param id ID of the DIA
    bool Contains(DIAId id) {
        //return data_.find(id) != data_.end();
        return data_.size() > id && id >= 0;
    }

    DIAId AllocateDIA() {
        SpacingLogger(true) << "Allocate DIA" << data_.size() - 1;
        //data_[nextId_] = std::unique_ptr<std::vector<Blob>>( new std::vector<Blob>() );
        data_.push_back( std::vector<Blob>() );
        return data_.size() - 1;
        //return nextId_++;
    }

    template<class T>
    BlockEmitter<T> GetLocalEmitter(DIAId id) {
        if (!Contains(id)) {
            throw std::runtime_error("target dia id unknown.");
        }
        auto& target = data_[id]; //yes. const ref to an unique_ptr
        return [& target](T elem){ target.push_back(Serialize(elem)); };
    }

private:
    DIAId nextId_;

    //YES I COULD just use a map of (int, vector) BUT then I have a weird
    //behaviour of std::map on inserts. Sometimes it randomly kills itself.
    //May depend on the compiler. Google it.    //std::map<DIAId, std::unique_ptr<std::vector<Blob>>> data_;
    std::vector<std::vector<Blob>> data_;
};

}
}

#endif // !C7A_DATA_DATA_MANAGER_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before>#include "SerialServiceHandler.h"
#include "SerialMessageProcessor.h"
#include "protocol/AmmoMessages.pb.h"

#ifdef WIN32
  #include <windows.h>
  #include <time.h>
#else
  #include <termios.h>
  #include <unistd.h>
#endif

#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#include <iostream>

#include "log.h"

using namespace std;

extern std::string gatewayAddress;
extern int gatewayPort;

SerialServiceHandler::SerialServiceHandler() :
messageProcessor(NULL),
sendQueueMutex(),
receiveQueueMutex()
{
#ifdef WIN32
  this->hComm = NULL;
#endif
}

int SerialServiceHandler::open(void *ptr)
{

  // Open the serial port.
#ifdef WIN32
  this->hComm = CreateFile( (const char*) ptr,
                           GENERIC_READ | GENERIC_WRITE,
                           0,
						   0,
						   OPEN_EXISTING,
						   0,
						   0);
  if (this->hComm == INVALID_HANDLE_VALUE) {
    int err = GetLastError();
    printf( "open %s error code: %d\n\n", (const char*) ptr, err );
    exit( -1 );
  }
#else
  // Open the port
  gFD = ::open( (const char *)ptr, O_RDWR | O_NOCTTY );// | O_NONBLOCK );
  if ( gFD == -1 )
  {
    printf( "open %s: error: %s\n\n", (const char *)ptr, strerror(errno)  );
    exit( -1 );
  }
#endif

  // Configure the serial port.
#ifdef WIN32
  DCB dcb;

  FillMemory(&dcb, sizeof(dcb), 0);
  dcb.DCBlength = sizeof(dcb);

  if (!BuildCommDCB("9600,n,8,1", &dcb)) {
    printf("could not build dcb: error %d\n", GetLastError());
    exit(-1);
  }

  if (!SetCommState(this->hComm, &dcb)) {
    printf("could not set comm state: error %d\n", GetLastError());
    CloseHandle(this->hComm);
    exit(-1);
  }
#else
  // Get the attributes for the port
  // struct termios config;
  // int result = tcgetattr( gFD, &config );
  // if ( result == -1 )
  // {
  //     perror( "tcgetattr" );
  //     exit( -1 );
  // }

  // // Set baud rate and 8, NONE, 1

  // // SETTING KEY:
  // // 1 -- ignore BREAK condition
  // // 2 -- map BREAK to SIGINTR
  // // 3 -- mark parity and framing errors
  // // 4 -- strip the 8th bit off chars
  // // 5 -- map NL to CR
  // // 6 -- ignore CR
  // // 7 -- map CR to NL
  // // 8 -- enable output flow control (software flow control)
  // // 9 -- enable input flow control (software flow control)
  // // 10-- any char will restart after stop (software flow control)
  // // 11-- postprocess output (not set = raw output)
  // // 12-- enable echoing of input characters
  // // 13-- echo NL
  // // 14-- enable canonical input (else raw)
  // // 15-- enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
  // // 16-- enable extended functions
  // // 17-- parity enable
  // // 18-- send 2 stop bits
  // // 19-- character size mask
  // // 20-- 8 bits
  // // 21-- enable follwing output processing

  // //		               1      2      3      4     5      6     7    8     9    10
  // config.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY);
  // //                  11
  // config.c_oflag &= ~OPOST;
  // //                   12    13     14    15    16
  // config.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
  // //		              17     18     19
  // //                 20
  // config.c_cflag |= CS8;
  // //                   21
  // config.c_cflag |= CRTSCTS;

  // config.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY);
  // config.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
  // config.c_cflag &= ~(PARENB|CSTOPB|CSIZE);
  // config.c_cflag |= CS8;

  // 	speed_t speed = B9600;

  // cfsetispeed(&config, speed);
  // cfsetospeed(&config, speed);

  // bzero(&config, sizeof(config) );
  // config.c_cflag = B9600 | CRTSCTS | CS8 | CLOCAL | CREAD;
  // config.c_iflag = IGNPAR | ICRNL;
  // config.c_oflag = 0;
  // //config.c_lflag = ICANON;
  // config.c_cc[VMIN] = 1;	// blocking read until 1 character arrives

  struct termios cfg;

  if (tcgetattr(gFD, &cfg))
  {
    close(gFD);
    // TODO: throw an exception
    return 0;
  }

  // Set baud rate
  cfsetispeed( &cfg, B9600 );
  cfsetospeed( &cfg, B9600 );

  cfmakeraw( &cfg );

  // Always set these
  cfg.c_cflag |= (CLOCAL | CREAD);

  // Set 8, None, 1
  cfg.c_cflag &= ~PARENB;
  cfg.c_cflag &= ~CSTOPB;
  cfg.c_cflag &= ~CSIZE;
  cfg.c_cflag |= CS8;

  // Enable hardware flow control
  cfg.c_cflag |= CRTSCTS;

  // Use raw input rather than canonical (line-oriented)
  cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

  // Disable software flow control
  cfg.c_iflag &= ~(IXON | IXOFF | IXANY);

  // Use raw output rather than processed (line-oriented)
  cfg.c_oflag &= ~OPOST;

  // Read one character at a time.  VTIME defaults to zero, so reads will
  // block indefinitely.
  cfg.c_cc[VMIN] = 1;

  // Other "c" bits
  //cfg.c_iflag |= IGNBRK; // Ignore break condition
  // The constant IUCLC is not present on OSX, so we only use it on non-OSX
  // platforms (where __APPLE__ is not defined).
  #ifndef __APPLE__
  cfg.c_iflag &= ~( IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC );
  #else
  cfg.c_iflag &= ~( IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL );
  #endif

  // Other "l" bits
  cfg.c_lflag &= ~IEXTEN;

  // Old, bad code. Sort of works, but was using canonical mode, which
  // we don't want.

  //struct termios config;
  //memset( &config, 0, sizeof(config) );
  //config.c_cflag = B9600 | CRTSCTS  | CS8 | CLOCAL | CREAD;
  //config.c_iflag = IGNPAR | ICRNL;
  //config.c_oflag = 0;
  //config.c_cc[VMIN] = 1;

  tcflush( gFD, TCIFLUSH );

  if (tcsetattr(gFD, TCSANOW, &cfg))
  {
    close(gFD);
    /* TODO: throw an exception */
    return 0;
  }

  // tcflush( gFD, TCIFLUSH );
  // tcsetattr( gFD, TCSANOW, &config );
#endif

  // Configure internal service handler state.

  state = READING_HEADER;
  collectedData = NULL;
  position = 0;

  dataToSend = NULL;
  position = 0;

  messageHeader.magicNumber = 0;
  messageHeader.size = 0;
  messageHeader.checksum = 0;
  messageHeader.headerChecksum = 0;

  sentMessageCount = 0;
  receivedMessageCount = 0;

  connectionClosing = false;

  messageProcessor = new SerialMessageProcessor(this);
  messageProcessor->activate();

  return 0;
}

#ifdef WIN32
#define DELTA_EPOCH_IN_MICROSECONDS 11644473600000000ULL
int gettimeofday(struct timeval* tv, struct timezone* tz)
{
  FILETIME ft;
  unsigned __int64 tmpres = 0;
  static int tzflag;

  if (NULL != tv) {
    GetSystemTimeAsFileTime(&ft);

	tmpres |= ft.dwHighDateTime;
	tmpres <<= 32;
	tmpres |= ft.dwLowDateTime;

	tmpres -= DELTA_EPOCH_IN_MICROSECONDS;
	tmpres /= 10;
	tv->tv_sec = (long) (tmpres / 1000000UL);
	tv->tv_usec = (long) (tmpres % 1000000UL);
  }

  return 0;
}
#endif

void SerialServiceHandler::receiveData() {

  char phone_id = 127;
  short size = 0;
  int state = 0;
  unsigned char c = 0;
  char buf[1024] = { '\0' };
  struct timeval tv;

  while ( true )
  {
    switch ( state )
    {
    case 0:
      // printf( "Waiting for magic.\n" ); fflush(stdout);
      c = read_a_char();
      if ( c == 0xef )
        state = c;
      break;

    case 0xef:
      c = read_a_char();
      if ( c == 0xbe || c == 0xef )
        state = c;
      else
        state = 0;
      break;

    case 0xbe:
      c = read_a_char();
      if ( c == 0xed )
        state = 1;
      else if ( c == 0xef )
        state = c;
      else
        state = 0;
      break;

    case 1:
      {
        for ( int i = 0; i < 13; ++i )
        {
          c = read_a_char();
          buf[i+3] = c;
        }
        phone_id = buf[3] & 0x3F;
        size = *(short *)&buf[4];

        state = 2;
      }
      break;

    case 2:
	    printf("SLOT[%2d],Len[%3d]: ", phone_id, size);

	    for ( int i = 0; i < size; ++i )
	    {
	      c = read_a_char();
	      buf[i+16] = c;
	    }
	    {
	      int result = gettimeofday( &tv, NULL );
	      if ( result == -1 )
	      {
	        printf( "gettimeofday() failed\n" );
	        break;
	      }

	      long ts = *(long *)&buf[8];
	      long rts = tv.tv_sec*1000 + tv.tv_usec / 1000;
	      printf( " Tdt(%ld),Thh(%ld),Tdel(%8ld)\n", rts, ts, rts-ts  );
	    }

	    processData(&buf[16], size, *(short  *)&buf[6], 0); // process the message
	    state = 0;
	    break;

	  default:
	    printf( "Something f-ed up.\n" );
	  }
	}

}

unsigned char SerialServiceHandler::read_a_char()
{
  unsigned char temp;

  while ( true )
  {
    // printf( "about to read()..." );
#ifdef WIN32
    DWORD count = 0;

	while (count == 0) {
      if (!ReadFile(this->hComm, &temp, 1, &count, NULL)) {
        int err = GetLastError();
        printf("ReadFile failed with error code: %d", err);
	    exit(-1);
      }
	  Sleep(1);
	}
#else
    ssize_t count = read( gFD, &temp, 1 );
#endif

    if ( count == -1 )
    {
      perror( "read" );
      exit( -1 );
    }
    else if ( count >= 1 )
    {
      break;
    }
    else if ( count == 0 )
    {
      perror( "read count 0" );
      exit( -1 );
    }
  }
  return temp;
}

int SerialServiceHandler::processData(char *data, unsigned int messageSize, unsigned int messageChecksum, char priority) {
  //Validate checksum
  unsigned int calculatedChecksum = ACE::crc32(data, messageSize);
  if( (calculatedChecksum & 0xffff) != (messageChecksum & 0xffff) ) {
    LOG_ERROR((long) this << " Mismatched checksum " << std::hex << calculatedChecksum << " : " << messageChecksum);
    LOG_ERROR((long) this << " size " << std::dec << messageSize ); // << " payload: " < );
    return -1;
  }

  //checksum is valid; parse the data
  ammo::protocol::MessageWrapper *msg = new ammo::protocol::MessageWrapper();
  bool result = msg->ParseFromArray(data, messageSize);
  if(result == false) {
    LOG_ERROR((long) this << " MessageWrapper could not be deserialized.");
    LOG_ERROR((long) this << " Client must have sent something that isn't a protocol buffer (or the wrong type).");
    delete msg;
    return -1;
  }
  addReceivedMessage(msg, priority);
  messageProcessor->signalNewMessageAvailable();

  return 0;
}

void SerialServiceHandler::sendMessage(ammo::protocol::MessageWrapper *msg, char priority) {
}

void SerialServiceHandler::sendErrorPacket(char errorCode) {
}

ammo::protocol::MessageWrapper *SerialServiceHandler::getNextMessageToSend() {
  ammo::protocol::MessageWrapper *msg = NULL;
  return msg;
}

ammo::protocol::MessageWrapper *SerialServiceHandler::getNextReceivedMessage() {
  ammo::protocol::MessageWrapper *msg = NULL;
  receiveQueueMutex.acquire();
  if(!receiveQueue.empty()) {
    msg = receiveQueue.top().message;
    receiveQueue.pop();
  }
  receiveQueueMutex.release();

  return msg;
}

void SerialServiceHandler::addReceivedMessage(ammo::protocol::MessageWrapper *msg, char priority) {
  QueuedMessage queuedMsg;
  queuedMsg.priority = priority;
  queuedMsg.message = msg;

  if(priority != msg->message_priority()) {
    LOG_WARN((long) this << " Priority mismatch on received message: Header = " << (int) priority << ", Message = " << msg->message_priority());
  }

  receiveQueueMutex.acquire();
  queuedMsg.messageCount = receivedMessageCount;
  receivedMessageCount++;
  receiveQueue.push(queuedMsg);
  receiveQueueMutex.release();
}

SerialServiceHandler::~SerialServiceHandler() {
  LOG_TRACE((long) this << " In ~SerialServiceHandler");
  delete messageProcessor;
}
<commit_msg>Fix buffer overflow if size is greater than maximum packet size (1024); convert printf logging to use gateway logging<commit_after>#include "SerialServiceHandler.h"
#include "SerialMessageProcessor.h"
#include "protocol/AmmoMessages.pb.h"

#ifdef WIN32
  #include <windows.h>
  #include <time.h>
#else
  #include <termios.h>
  #include <unistd.h>
#endif

#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#include <iostream>

#include "log.h"

const size_t MAX_PAYLOAD_SIZE = 1024;

using namespace std;

extern std::string gatewayAddress;
extern int gatewayPort;

SerialServiceHandler::SerialServiceHandler() :
messageProcessor(NULL),
sendQueueMutex(),
receiveQueueMutex()
{
#ifdef WIN32
  this->hComm = NULL;
#endif
}

int SerialServiceHandler::open(void *ptr)
{

  // Open the serial port.
#ifdef WIN32
  this->hComm = CreateFile( (const char*) ptr,
                           GENERIC_READ | GENERIC_WRITE,
                           0,
						   0,
						   OPEN_EXISTING,
						   0,
						   0);
  if (this->hComm == INVALID_HANDLE_VALUE) {
    int err = GetLastError();
    LOG_ERROR("open "<< (const char *) ptr << " error code: " << err );
    exit( -1 );
  }
#else
  // Open the port
  gFD = ::open( (const char *)ptr, O_RDWR | O_NOCTTY );// | O_NONBLOCK );
  if ( gFD == -1 )
  {
    LOG_ERROR("open "<< (const char *) ptr << ": error: " << strerror(errno));
    exit( -1 );
  }
#endif

  // Configure the serial port.
#ifdef WIN32
  DCB dcb;

  FillMemory(&dcb, sizeof(dcb), 0);
  dcb.DCBlength = sizeof(dcb);

  if (!BuildCommDCB("9600,n,8,1", &dcb)) {
    LOG_ERROR("could not build dcb: error " << GetLastError());
    exit(-1);
  }

  if (!SetCommState(this->hComm, &dcb)) {
    LOG_ERROR("could not set comm state: error " << GetLastError());
    CloseHandle(this->hComm);
    exit(-1);
  }
#else
  // Get the attributes for the port
  // struct termios config;
  // int result = tcgetattr( gFD, &config );
  // if ( result == -1 )
  // {
  //     perror( "tcgetattr" );
  //     exit( -1 );
  // }

  // // Set baud rate and 8, NONE, 1

  // // SETTING KEY:
  // // 1 -- ignore BREAK condition
  // // 2 -- map BREAK to SIGINTR
  // // 3 -- mark parity and framing errors
  // // 4 -- strip the 8th bit off chars
  // // 5 -- map NL to CR
  // // 6 -- ignore CR
  // // 7 -- map CR to NL
  // // 8 -- enable output flow control (software flow control)
  // // 9 -- enable input flow control (software flow control)
  // // 10-- any char will restart after stop (software flow control)
  // // 11-- postprocess output (not set = raw output)
  // // 12-- enable echoing of input characters
  // // 13-- echo NL
  // // 14-- enable canonical input (else raw)
  // // 15-- enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
  // // 16-- enable extended functions
  // // 17-- parity enable
  // // 18-- send 2 stop bits
  // // 19-- character size mask
  // // 20-- 8 bits
  // // 21-- enable follwing output processing

  // //		               1      2      3      4     5      6     7    8     9    10
  // config.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY);
  // //                  11
  // config.c_oflag &= ~OPOST;
  // //                   12    13     14    15    16
  // config.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
  // //		              17     18     19
  // //                 20
  // config.c_cflag |= CS8;
  // //                   21
  // config.c_cflag |= CRTSCTS;

  // config.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY);
  // config.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
  // config.c_cflag &= ~(PARENB|CSTOPB|CSIZE);
  // config.c_cflag |= CS8;

  // 	speed_t speed = B9600;

  // cfsetispeed(&config, speed);
  // cfsetospeed(&config, speed);

  // bzero(&config, sizeof(config) );
  // config.c_cflag = B9600 | CRTSCTS | CS8 | CLOCAL | CREAD;
  // config.c_iflag = IGNPAR | ICRNL;
  // config.c_oflag = 0;
  // //config.c_lflag = ICANON;
  // config.c_cc[VMIN] = 1;	// blocking read until 1 character arrives

  struct termios cfg;

  if (tcgetattr(gFD, &cfg))
  {
    close(gFD);
    // TODO: throw an exception
    return 0;
  }

  // Set baud rate
  cfsetispeed( &cfg, B9600 );
  cfsetospeed( &cfg, B9600 );

  cfmakeraw( &cfg );

  // Always set these
  cfg.c_cflag |= (CLOCAL | CREAD);

  // Set 8, None, 1
  cfg.c_cflag &= ~PARENB;
  cfg.c_cflag &= ~CSTOPB;
  cfg.c_cflag &= ~CSIZE;
  cfg.c_cflag |= CS8;

  // Enable hardware flow control
  cfg.c_cflag |= CRTSCTS;

  // Use raw input rather than canonical (line-oriented)
  cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

  // Disable software flow control
  cfg.c_iflag &= ~(IXON | IXOFF | IXANY);

  // Use raw output rather than processed (line-oriented)
  cfg.c_oflag &= ~OPOST;

  // Read one character at a time.  VTIME defaults to zero, so reads will
  // block indefinitely.
  cfg.c_cc[VMIN] = 1;

  // Other "c" bits
  //cfg.c_iflag |= IGNBRK; // Ignore break condition
  // The constant IUCLC is not present on OSX, so we only use it on non-OSX
  // platforms (where __APPLE__ is not defined).
  #ifndef __APPLE__
  cfg.c_iflag &= ~( IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC );
  #else
  cfg.c_iflag &= ~( IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL );
  #endif

  // Other "l" bits
  cfg.c_lflag &= ~IEXTEN;

  // Old, bad code. Sort of works, but was using canonical mode, which
  // we don't want.

  //struct termios config;
  //memset( &config, 0, sizeof(config) );
  //config.c_cflag = B9600 | CRTSCTS  | CS8 | CLOCAL | CREAD;
  //config.c_iflag = IGNPAR | ICRNL;
  //config.c_oflag = 0;
  //config.c_cc[VMIN] = 1;

  tcflush( gFD, TCIFLUSH );

  if (tcsetattr(gFD, TCSANOW, &cfg))
  {
    close(gFD);
    /* TODO: throw an exception */
    return 0;
  }

  // tcflush( gFD, TCIFLUSH );
  // tcsetattr( gFD, TCSANOW, &config );
#endif

  // Configure internal service handler state.

  state = READING_HEADER;
  collectedData = NULL;
  position = 0;

  dataToSend = NULL;
  position = 0;

  messageHeader.magicNumber = 0;
  messageHeader.size = 0;
  messageHeader.checksum = 0;
  messageHeader.headerChecksum = 0;

  sentMessageCount = 0;
  receivedMessageCount = 0;

  connectionClosing = false;

  messageProcessor = new SerialMessageProcessor(this);
  messageProcessor->activate();

  return 0;
}

//TODO: ACE provides gettimeofday; we shouldn't reimplement it
#ifdef WIN32
#define DELTA_EPOCH_IN_MICROSECONDS 11644473600000000ULL
int gettimeofday(struct timeval* tv, struct timezone* tz)
{
  FILETIME ft;
  unsigned __int64 tmpres = 0;
  static int tzflag;

  if (NULL != tv) {
    GetSystemTimeAsFileTime(&ft);

	tmpres |= ft.dwHighDateTime;
	tmpres <<= 32;
	tmpres |= ft.dwLowDateTime;

	tmpres -= DELTA_EPOCH_IN_MICROSECONDS;
	tmpres /= 10;
	tv->tv_sec = (long) (tmpres / 1000000UL);
	tv->tv_usec = (long) (tmpres % 1000000UL);
  }

  return 0;
}
#endif

void SerialServiceHandler::receiveData() {

  char phone_id = 127;
  unsigned short size = 0;
  int state = 0;
  unsigned char c = 0;
  char buf[MAX_PAYLOAD_SIZE] = { '\0' };
  struct timeval tv;

  while ( true )
  {
    switch ( state )
    {
    case 0:
      // printf( "Waiting for magic.\n" ); fflush(stdout);
      c = read_a_char();
      if ( c == 0xef )
        state = c;
      break;

    case 0xef:
      c = read_a_char();
      if ( c == 0xbe || c == 0xef )
        state = c;
      else
        state = 0;
      break;

    case 0xbe:
      c = read_a_char();
      if ( c == 0xed )
        state = 1;
      else if ( c == 0xef )
        state = c;
      else
        state = 0;
      break;

    case 1:
      {
        for ( int i = 0; i < 13; ++i )
        {
          c = read_a_char();
          buf[i+3] = c;
        }
        phone_id = buf[3] & 0x3F;
        size = *(short *)&buf[4];

        state = 2;
      }
      break;

    case 2:
	    LOG_DEBUG("SLOT[" << phone_id << "],Len[" << size << "]: ");

	    if(size < MAX_PAYLOAD_SIZE - 16) {
        for (unsigned short i = 0; i < size; ++i)
        {
          c = read_a_char();
          buf[i+16] = c;
        }
        {
          int result = gettimeofday( &tv, NULL );
          if ( result == -1 )
          {
            LOG_ERROR("gettimeofday() failed\n" );
            break;
          }

          long ts = *(long *)&buf[8];
          long rts = tv.tv_sec*1000 + tv.tv_usec / 1000;
          LOG_DEBUG(" Tdt(" << rts << "),Thh(" << ts << "),Tdel(" << rts - ts << ")");
        }

        processData(&buf[16], size, *(short  *)&buf[6], 0); // process the message
	    } else {
	      LOG_ERROR("Received packet of invalid size: " << size);
	    }
	    state = 0;
	    break;

	  default:
	    LOG_ERROR("SerialServiceHandler: unknown state");
	  }
	}

}

unsigned char SerialServiceHandler::read_a_char()
{
  unsigned char temp;

  while ( true )
  {
    // printf( "about to read()..." );
#ifdef WIN32
    DWORD count = 0;

	while (count == 0) {
      if (!ReadFile(this->hComm, &temp, 1, &count, NULL)) {
        int err = GetLastError();
        LOG_ERROR("ReadFile failed with error code: " << err);
	    exit(-1);
      }
	  Sleep(1);
	}
#else
    ssize_t count = read( gFD, &temp, 1 );
#endif

    if ( count == -1 )
    {
      LOG_ERROR( "Read returned -1" );
      exit( -1 );
    }
    else if ( count >= 1 )
    {
      break;
    }
    else if ( count == 0 )
    {
      LOG_ERROR( "Read returned 0" );
      exit( -1 );
    }
  }
  return temp;
}

int SerialServiceHandler::processData(char *data, unsigned int messageSize, unsigned int messageChecksum, char priority) {
  //Validate checksum
  unsigned int calculatedChecksum = ACE::crc32(data, messageSize);
  if( (calculatedChecksum & 0xffff) != (messageChecksum & 0xffff) ) {
    LOG_ERROR((long) this << " Mismatched checksum " << std::hex << calculatedChecksum << " : " << messageChecksum);
    LOG_ERROR((long) this << " size " << std::dec << messageSize ); // << " payload: " < );
    return -1;
  }

  //checksum is valid; parse the data
  ammo::protocol::MessageWrapper *msg = new ammo::protocol::MessageWrapper();
  bool result = msg->ParseFromArray(data, messageSize);
  if(result == false) {
    LOG_ERROR((long) this << " MessageWrapper could not be deserialized.");
    LOG_ERROR((long) this << " Client must have sent something that isn't a protocol buffer (or the wrong type).");
    delete msg;
    return -1;
  }
  addReceivedMessage(msg, priority);
  messageProcessor->signalNewMessageAvailable();

  return 0;
}

void SerialServiceHandler::sendMessage(ammo::protocol::MessageWrapper *msg, char priority) {
}

void SerialServiceHandler::sendErrorPacket(char errorCode) {
}

ammo::protocol::MessageWrapper *SerialServiceHandler::getNextMessageToSend() {
  ammo::protocol::MessageWrapper *msg = NULL;
  return msg;
}

ammo::protocol::MessageWrapper *SerialServiceHandler::getNextReceivedMessage() {
  ammo::protocol::MessageWrapper *msg = NULL;
  receiveQueueMutex.acquire();
  if(!receiveQueue.empty()) {
    msg = receiveQueue.top().message;
    receiveQueue.pop();
  }
  receiveQueueMutex.release();

  return msg;
}

void SerialServiceHandler::addReceivedMessage(ammo::protocol::MessageWrapper *msg, char priority) {
  QueuedMessage queuedMsg;
  queuedMsg.priority = priority;
  queuedMsg.message = msg;

  if(priority != msg->message_priority()) {
    LOG_WARN((long) this << " Priority mismatch on received message: Header = " << (int) priority << ", Message = " << msg->message_priority());
  }

  receiveQueueMutex.acquire();
  queuedMsg.messageCount = receivedMessageCount;
  receivedMessageCount++;
  receiveQueue.push(queuedMsg);
  receiveQueueMutex.release();
}

SerialServiceHandler::~SerialServiceHandler() {
  LOG_TRACE((long) this << " In ~SerialServiceHandler");
  delete messageProcessor;
}
<|endoftext|>


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

#include <catch.hpp>

#include <acl/math/scalar_32.h>
#include <acl/math/scalar_64.h>

#include <limits>

using namespace acl;

template<typename FloatType>
static void TestScalarImpl(const FloatType pi, const FloatType threshold)
{
	const FloatType half_pi = pi * FloatType(0.5);
	const FloatType two_pi = pi * FloatType(2.0);

	REQUIRE(acl::floor(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(acl::floor(FloatType(0.5)) == FloatType(0.0));
	REQUIRE(acl::floor(FloatType(2.5)) == FloatType(2.0));
	REQUIRE(acl::floor(FloatType(3.0)) == FloatType(3.0));
	REQUIRE(acl::floor(FloatType(-0.5)) == FloatType(-1.0));
	REQUIRE(acl::floor(FloatType(-2.5)) == FloatType(-3.0));
	REQUIRE(acl::floor(FloatType(-3.0)) == FloatType(-3.0));

	REQUIRE(acl::ceil(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(acl::ceil(FloatType(0.5)) == FloatType(1.0));
	REQUIRE(acl::ceil(FloatType(2.5)) == FloatType(3.0));
	REQUIRE(acl::ceil(FloatType(3.0)) == FloatType(3.0));
	REQUIRE(acl::ceil(FloatType(-0.5)) == FloatType(0.0));
	REQUIRE(acl::ceil(FloatType(-2.5)) == FloatType(-2.0));
	REQUIRE(acl::ceil(FloatType(-3.0)) == FloatType(-3.0));

	REQUIRE(clamp(FloatType(0.5), FloatType(0.0), FloatType(1.0)) == FloatType(0.5));
	REQUIRE(clamp(FloatType(-0.5), FloatType(0.0), FloatType(1.0)) == FloatType(0.0));
	REQUIRE(clamp(FloatType(1.5), FloatType(0.0), FloatType(1.0)) == FloatType(1.0));

	REQUIRE(acl::abs(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(acl::abs(FloatType(2.0)) == FloatType(2.0));
	REQUIRE(acl::abs(FloatType(-2.0)) == FloatType(2.0));

	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(1.0), FloatType(0.00001)) == true);
	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(1.000001), FloatType(0.00001)) == true);
	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(0.999999), FloatType(0.00001)) == true);
	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(1.001), FloatType(0.00001)) == false);
	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(0.999), FloatType(0.00001)) == false);

	REQUIRE(acl::sqrt(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(scalar_near_equal(acl::sqrt(FloatType(0.5)), std::sqrt(FloatType(0.5)), threshold));
	REQUIRE(scalar_near_equal(acl::sqrt(FloatType(32.5)), std::sqrt(FloatType(32.5)), threshold));

	REQUIRE(scalar_near_equal(acl::sqrt_reciprocal(FloatType(0.5)), FloatType(1.0) / std::sqrt(FloatType(0.5)), threshold));
	REQUIRE(scalar_near_equal(acl::sqrt_reciprocal(FloatType(32.5)), FloatType(1.0) / std::sqrt(FloatType(32.5)), threshold));

	REQUIRE(scalar_near_equal(acl::reciprocal(FloatType(0.5)), FloatType(1.0 / 0.5), threshold));
	REQUIRE(scalar_near_equal(acl::reciprocal(FloatType(32.5)), FloatType(1.0 / 32.5), threshold));
	REQUIRE(scalar_near_equal(acl::reciprocal(FloatType(-0.5)), FloatType(1.0 / -0.5), threshold));
	REQUIRE(scalar_near_equal(acl::reciprocal(FloatType(-32.5)), FloatType(1.0 / -32.5), threshold));

	const FloatType angles[] = { FloatType(0.0), pi, -pi, half_pi, -half_pi, FloatType(0.5), FloatType(32.5), FloatType(-0.5), FloatType(-32.5) };

	for (const FloatType angle : angles)
	{
		REQUIRE(scalar_near_equal(acl::sin(angle), std::sin(angle), threshold));
		REQUIRE(scalar_near_equal(acl::cos(angle), std::cos(angle), threshold));

		FloatType sin_result;
		FloatType cos_result;
		acl::sincos(angle, sin_result, cos_result);
		REQUIRE(scalar_near_equal(sin_result, std::sin(angle), threshold));
		REQUIRE(scalar_near_equal(cos_result, std::cos(angle), threshold));
	}

	REQUIRE(scalar_near_equal(acl::acos(FloatType(-1.0)), std::acos(FloatType(-1.0)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(-0.75)), std::acos(FloatType(-0.75)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(-0.5)), std::acos(FloatType(-0.5)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(-0.25)), std::acos(-FloatType(0.25)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(0.0)), std::acos(FloatType(0.0)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(0.25)), std::acos(FloatType(0.25)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(0.5)), std::acos(FloatType(0.5)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(0.75)), std::acos(FloatType(0.75)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(1.0)), std::acos(FloatType(1.0)), threshold));

	REQUIRE(scalar_near_equal(acl::atan2(FloatType(-2.0), FloatType(-2.0)), std::atan2(FloatType(-2.0), FloatType(-2.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(-1.0), FloatType(-2.0)), std::atan2(FloatType(-1.0), FloatType(-2.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(-2.0), FloatType(-1.0)), std::atan2(FloatType(-2.0), FloatType(-1.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(2.0), FloatType(2.0)), std::atan2(FloatType(2.0), FloatType(2.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(1.0), FloatType(2.0)), std::atan2(FloatType(1.0), FloatType(2.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(2.0), FloatType(1.0)), std::atan2(FloatType(2.0), FloatType(1.0)), threshold));

	REQUIRE(acl::min(FloatType(-0.5), FloatType(1.0)) == FloatType(-0.5));
	REQUIRE(acl::min(FloatType(1.0), FloatType(-0.5)) == FloatType(-0.5));
	REQUIRE(acl::min(FloatType(1.0), FloatType(1.0)) == FloatType(1.0));

	REQUIRE(acl::max(FloatType(-0.5), FloatType(1.0)) == FloatType(1.0));
	REQUIRE(acl::max(FloatType(1.0), FloatType(-0.5)) == FloatType(1.0));
	REQUIRE(acl::max(FloatType(1.0), FloatType(1.0)) == FloatType(1.0));

	REQUIRE(deg2rad(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(90.0)), half_pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(-90.0)), -half_pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(180.0)), pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(-180.0)), -pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(360.0)), two_pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(-360.0)), -two_pi, threshold));

	REQUIRE(acl::is_finite(FloatType(0.0)) == true);
	REQUIRE(acl::is_finite(FloatType(32.0)) == true);
	REQUIRE(acl::is_finite(FloatType(-32.0)) == true);
	REQUIRE(acl::is_finite(std::numeric_limits<FloatType>::infinity()) == false);
	REQUIRE(acl::is_finite(std::numeric_limits<FloatType>::quiet_NaN()) == false);
	REQUIRE(acl::is_finite(std::numeric_limits<FloatType>::signaling_NaN()) == false);

	REQUIRE(symmetric_round(FloatType(-1.75)) == FloatType(-2.0));
	REQUIRE(symmetric_round(FloatType(-1.5)) == FloatType(-2.0));
	REQUIRE(symmetric_round(FloatType(-1.4999)) == FloatType(-1.0));
	REQUIRE(symmetric_round(FloatType(-0.5)) == FloatType(-1.0));
	REQUIRE(symmetric_round(FloatType(-0.4999)) == FloatType(0.0));
	REQUIRE(symmetric_round(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(symmetric_round(FloatType(0.4999)) == FloatType(0.0));
	REQUIRE(symmetric_round(FloatType(0.5)) == FloatType(1.0));
	REQUIRE(symmetric_round(FloatType(1.4999)) == FloatType(1.0));
	REQUIRE(symmetric_round(FloatType(1.5)) == FloatType(2.0));
	REQUIRE(symmetric_round(FloatType(1.75)) == FloatType(2.0));

	REQUIRE(fraction(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(fraction(FloatType(1.0)) == FloatType(0.0));
	REQUIRE(fraction(FloatType(-1.0)) == FloatType(0.0));
	REQUIRE(scalar_near_equal(fraction(FloatType(0.25)), FloatType(0.25), threshold));
	REQUIRE(scalar_near_equal(fraction(FloatType(0.5)), FloatType(0.5), threshold));
	REQUIRE(scalar_near_equal(fraction(FloatType(0.75)), FloatType(0.75), threshold));
}

TEST_CASE("scalar 32 math", "[math][scalar]")
{
	TestScalarImpl<float>(acl::k_pi_32, 1.0e-6f);
}

TEST_CASE("scalar 64 math", "[math][scalar]")
{
	TestScalarImpl<double>(acl::k_pi_64, 1.0e-9);
}
<commit_msg>Renamed function to be consistent with naming convention.<commit_after>////////////////////////////////////////////////////////////////////////////////
// The MIT License (MIT)
//
// Copyright (c) 2018 Nicholas Frechette & Animation Compression Library contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
////////////////////////////////////////////////////////////////////////////////

#include <catch.hpp>

#include <acl/math/scalar_32.h>
#include <acl/math/scalar_64.h>

#include <limits>

using namespace acl;

template<typename FloatType>
static void test_scalar_impl(const FloatType pi, const FloatType threshold)
{
	const FloatType half_pi = pi * FloatType(0.5);
	const FloatType two_pi = pi * FloatType(2.0);

	REQUIRE(acl::floor(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(acl::floor(FloatType(0.5)) == FloatType(0.0));
	REQUIRE(acl::floor(FloatType(2.5)) == FloatType(2.0));
	REQUIRE(acl::floor(FloatType(3.0)) == FloatType(3.0));
	REQUIRE(acl::floor(FloatType(-0.5)) == FloatType(-1.0));
	REQUIRE(acl::floor(FloatType(-2.5)) == FloatType(-3.0));
	REQUIRE(acl::floor(FloatType(-3.0)) == FloatType(-3.0));

	REQUIRE(acl::ceil(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(acl::ceil(FloatType(0.5)) == FloatType(1.0));
	REQUIRE(acl::ceil(FloatType(2.5)) == FloatType(3.0));
	REQUIRE(acl::ceil(FloatType(3.0)) == FloatType(3.0));
	REQUIRE(acl::ceil(FloatType(-0.5)) == FloatType(0.0));
	REQUIRE(acl::ceil(FloatType(-2.5)) == FloatType(-2.0));
	REQUIRE(acl::ceil(FloatType(-3.0)) == FloatType(-3.0));

	REQUIRE(clamp(FloatType(0.5), FloatType(0.0), FloatType(1.0)) == FloatType(0.5));
	REQUIRE(clamp(FloatType(-0.5), FloatType(0.0), FloatType(1.0)) == FloatType(0.0));
	REQUIRE(clamp(FloatType(1.5), FloatType(0.0), FloatType(1.0)) == FloatType(1.0));

	REQUIRE(acl::abs(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(acl::abs(FloatType(2.0)) == FloatType(2.0));
	REQUIRE(acl::abs(FloatType(-2.0)) == FloatType(2.0));

	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(1.0), FloatType(0.00001)) == true);
	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(1.000001), FloatType(0.00001)) == true);
	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(0.999999), FloatType(0.00001)) == true);
	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(1.001), FloatType(0.00001)) == false);
	REQUIRE(scalar_near_equal(FloatType(1.0), FloatType(0.999), FloatType(0.00001)) == false);

	REQUIRE(acl::sqrt(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(scalar_near_equal(acl::sqrt(FloatType(0.5)), std::sqrt(FloatType(0.5)), threshold));
	REQUIRE(scalar_near_equal(acl::sqrt(FloatType(32.5)), std::sqrt(FloatType(32.5)), threshold));

	REQUIRE(scalar_near_equal(acl::sqrt_reciprocal(FloatType(0.5)), FloatType(1.0) / std::sqrt(FloatType(0.5)), threshold));
	REQUIRE(scalar_near_equal(acl::sqrt_reciprocal(FloatType(32.5)), FloatType(1.0) / std::sqrt(FloatType(32.5)), threshold));

	REQUIRE(scalar_near_equal(acl::reciprocal(FloatType(0.5)), FloatType(1.0 / 0.5), threshold));
	REQUIRE(scalar_near_equal(acl::reciprocal(FloatType(32.5)), FloatType(1.0 / 32.5), threshold));
	REQUIRE(scalar_near_equal(acl::reciprocal(FloatType(-0.5)), FloatType(1.0 / -0.5), threshold));
	REQUIRE(scalar_near_equal(acl::reciprocal(FloatType(-32.5)), FloatType(1.0 / -32.5), threshold));

	const FloatType angles[] = { FloatType(0.0), pi, -pi, half_pi, -half_pi, FloatType(0.5), FloatType(32.5), FloatType(-0.5), FloatType(-32.5) };

	for (const FloatType angle : angles)
	{
		REQUIRE(scalar_near_equal(acl::sin(angle), std::sin(angle), threshold));
		REQUIRE(scalar_near_equal(acl::cos(angle), std::cos(angle), threshold));

		FloatType sin_result;
		FloatType cos_result;
		acl::sincos(angle, sin_result, cos_result);
		REQUIRE(scalar_near_equal(sin_result, std::sin(angle), threshold));
		REQUIRE(scalar_near_equal(cos_result, std::cos(angle), threshold));
	}

	REQUIRE(scalar_near_equal(acl::acos(FloatType(-1.0)), std::acos(FloatType(-1.0)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(-0.75)), std::acos(FloatType(-0.75)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(-0.5)), std::acos(FloatType(-0.5)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(-0.25)), std::acos(-FloatType(0.25)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(0.0)), std::acos(FloatType(0.0)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(0.25)), std::acos(FloatType(0.25)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(0.5)), std::acos(FloatType(0.5)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(0.75)), std::acos(FloatType(0.75)), threshold));
	REQUIRE(scalar_near_equal(acl::acos(FloatType(1.0)), std::acos(FloatType(1.0)), threshold));

	REQUIRE(scalar_near_equal(acl::atan2(FloatType(-2.0), FloatType(-2.0)), std::atan2(FloatType(-2.0), FloatType(-2.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(-1.0), FloatType(-2.0)), std::atan2(FloatType(-1.0), FloatType(-2.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(-2.0), FloatType(-1.0)), std::atan2(FloatType(-2.0), FloatType(-1.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(2.0), FloatType(2.0)), std::atan2(FloatType(2.0), FloatType(2.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(1.0), FloatType(2.0)), std::atan2(FloatType(1.0), FloatType(2.0)), threshold));
	REQUIRE(scalar_near_equal(acl::atan2(FloatType(2.0), FloatType(1.0)), std::atan2(FloatType(2.0), FloatType(1.0)), threshold));

	REQUIRE(acl::min(FloatType(-0.5), FloatType(1.0)) == FloatType(-0.5));
	REQUIRE(acl::min(FloatType(1.0), FloatType(-0.5)) == FloatType(-0.5));
	REQUIRE(acl::min(FloatType(1.0), FloatType(1.0)) == FloatType(1.0));

	REQUIRE(acl::max(FloatType(-0.5), FloatType(1.0)) == FloatType(1.0));
	REQUIRE(acl::max(FloatType(1.0), FloatType(-0.5)) == FloatType(1.0));
	REQUIRE(acl::max(FloatType(1.0), FloatType(1.0)) == FloatType(1.0));

	REQUIRE(deg2rad(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(90.0)), half_pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(-90.0)), -half_pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(180.0)), pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(-180.0)), -pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(360.0)), two_pi, threshold));
	REQUIRE(scalar_near_equal(deg2rad(FloatType(-360.0)), -two_pi, threshold));

	REQUIRE(acl::is_finite(FloatType(0.0)) == true);
	REQUIRE(acl::is_finite(FloatType(32.0)) == true);
	REQUIRE(acl::is_finite(FloatType(-32.0)) == true);
	REQUIRE(acl::is_finite(std::numeric_limits<FloatType>::infinity()) == false);
	REQUIRE(acl::is_finite(std::numeric_limits<FloatType>::quiet_NaN()) == false);
	REQUIRE(acl::is_finite(std::numeric_limits<FloatType>::signaling_NaN()) == false);

	REQUIRE(symmetric_round(FloatType(-1.75)) == FloatType(-2.0));
	REQUIRE(symmetric_round(FloatType(-1.5)) == FloatType(-2.0));
	REQUIRE(symmetric_round(FloatType(-1.4999)) == FloatType(-1.0));
	REQUIRE(symmetric_round(FloatType(-0.5)) == FloatType(-1.0));
	REQUIRE(symmetric_round(FloatType(-0.4999)) == FloatType(0.0));
	REQUIRE(symmetric_round(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(symmetric_round(FloatType(0.4999)) == FloatType(0.0));
	REQUIRE(symmetric_round(FloatType(0.5)) == FloatType(1.0));
	REQUIRE(symmetric_round(FloatType(1.4999)) == FloatType(1.0));
	REQUIRE(symmetric_round(FloatType(1.5)) == FloatType(2.0));
	REQUIRE(symmetric_round(FloatType(1.75)) == FloatType(2.0));

	REQUIRE(fraction(FloatType(0.0)) == FloatType(0.0));
	REQUIRE(fraction(FloatType(1.0)) == FloatType(0.0));
	REQUIRE(fraction(FloatType(-1.0)) == FloatType(0.0));
	REQUIRE(scalar_near_equal(fraction(FloatType(0.25)), FloatType(0.25), threshold));
	REQUIRE(scalar_near_equal(fraction(FloatType(0.5)), FloatType(0.5), threshold));
	REQUIRE(scalar_near_equal(fraction(FloatType(0.75)), FloatType(0.75), threshold));
}

TEST_CASE("scalar 32 math", "[math][scalar]")
{
	test_scalar_impl<float>(acl::k_pi_32, 1.0e-6f);
}

TEST_CASE("scalar 64 math", "[math][scalar]")
{
	test_scalar_impl<double>(acl::k_pi_64, 1.0e-9);
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>
#include "log4cpp/FixedContextCategory.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"
#include "log4cpp/NDC.hh"

int main(int argc, char** argv) {
    log4cpp::Appender* appender =
        new log4cpp::OstreamAppender("default", &std::cout);

    log4cpp::Layout* layout = new log4cpp::BasicLayout();
    appender->setLayout(layout);

    log4cpp::Category& root = log4cpp::Category::getRoot();
    root.setAppender(appender);
       root.setPriority(log4cpp::Priority::ERROR);

    log4cpp::FixedContextCategory sub1 =
        log4cpp::FixedContextCategory(std::string("sub1"), std::string("context1"));

    log4cpp::FixedContextCategory sub1_2 =
        log4cpp::FixedContextCategory(std::string("sub1"), std::string("context1_2"));

    log4cpp::FixedContextCategory sub2 =
        log4cpp::FixedContextCategory(std::string("sub1.sub2"), std::string("context2"));

    std::cout << " root priority = " << root.getPriority() << std::endl;
    std::cout << " sub1 priority = " << sub1.getPriority() << std::endl;
    std::cout << " sub2 priority = " << sub2.getPriority() << std::endl;

    root.error("root error");
    root.warn("root warn");
    sub1.error("sub1 error");
    sub1.warn("sub1 warn");
    sub1_2.error("sub1 error");
    sub1_2.warn("sub1 warn");
    sub2.error("sub2 error");
    sub2.warn("sub2 warn");

    log4cpp::Category::getInstance(std::string("sub1")).
               setPriority(log4cpp::Priority::INFO);

    std::cout << " root priority = " << root.getPriority() << std::endl;
    std::cout << " sub1 priority = " << sub1.getPriority() << std::endl;
    std::cout << " sub2 priority = " << sub2.getPriority() << std::endl;

    std::cout << "priority info" << std::endl;
    root.error("root error");
    root.warn("root warn");
    sub1.error("sub1 error");
    sub1.warn("sub1 warn");
    sub2.error("sub2 error");
    sub2.warn("sub2 warn");
    sub2.error("%s %s %d", "test", "vform", 123);
    sub2.warnStream() << "streamed warn";

    sub2 << log4cpp::Priority::WARN << "warn2.." << "..warn3..value=" << 0 <<
        log4cpp::CategoryStream::ENDLINE << "..warn4";

    log4cpp::Category::shutdown();

    return 0;
}
<commit_msg>Use contructor for FixedContextCategory instead of assignment.<commit_after>#include <stdio.h>
#include <iostream>
#include "log4cpp/FixedContextCategory.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"
#include "log4cpp/NDC.hh"

int main(int argc, char** argv) {
    log4cpp::Appender* appender =
        new log4cpp::OstreamAppender("default", &std::cout);

    log4cpp::Layout* layout = new log4cpp::BasicLayout();
    appender->setLayout(layout);

    log4cpp::Category& root = log4cpp::Category::getRoot();
    root.setAppender(appender);
       root.setPriority(log4cpp::Priority::ERROR);

    log4cpp::FixedContextCategory sub1(std::string("sub1"), std::string("context1"));

    log4cpp::FixedContextCategory sub1_2(std::string("sub1"), std::string("context1_2"));

    log4cpp::FixedContextCategory sub2(std::string("sub1.sub2"), std::string("context2"));

    std::cout << " root priority = " << root.getPriority() << std::endl;
    std::cout << " sub1 priority = " << sub1.getPriority() << std::endl;
    std::cout << " sub2 priority = " << sub2.getPriority() << std::endl;

    root.error("root error");
    root.warn("root warn");
    sub1.error("sub1 error");
    sub1.warn("sub1 warn");
    sub1_2.error("sub1 error");
    sub1_2.warn("sub1 warn");
    sub2.error("sub2 error");
    sub2.warn("sub2 warn");

    log4cpp::Category::getInstance(std::string("sub1")).
               setPriority(log4cpp::Priority::INFO);

    std::cout << " root priority = " << root.getPriority() << std::endl;
    std::cout << " sub1 priority = " << sub1.getPriority() << std::endl;
    std::cout << " sub2 priority = " << sub2.getPriority() << std::endl;

    std::cout << "priority info" << std::endl;
    root.error("root error");
    root.warn("root warn");
    sub1.error("sub1 error");
    sub1.warn("sub1 warn");
    sub2.error("sub2 error");
    sub2.warn("sub2 warn");
    sub2.error("%s %s %d", "test", "vform", 123);
    sub2.warnStream() << "streamed warn";

    sub2 << log4cpp::Priority::WARN << "warn2.." << "..warn3..value=" << 0 <<
        log4cpp::CategoryStream::ENDLINE << "..warn4";

    log4cpp::Category::shutdown();

    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "catch.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

namespace ea_kernels
{

void velocity_function(const Vector &x, Vector &v)
{
   int dim = x.Size();
   switch (dim)
   {
      case 1: v(0) = 1.0; break;
      case 2: v(0) = x(1); v(1) = -x(0); break;
      case 3: v(0) = x(1); v(1) = -x(0); v(2) = x(0); break;
   }
}

void AddConvectionIntegrators(BilinearForm &k, VectorCoefficient &velocity,
                              bool dg)
{
   k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));

   if (dg)
   {
      k.AddInteriorFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
      k.AddBdrFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
   }
}

void test_ea(Mesh &&mesh, int order, bool dg, const int pb)
{
   mesh.EnsureNodes();
   mesh.SetCurvature(mesh.GetNodalFESpace()->GetOrder(0));
   int dim = mesh.Dimension();

   FiniteElementCollection *fec;
   if (dg)
   {
      fec = new L2_FECollection(order, dim, BasisType::GaussLobatto);
   }
   else
   {
      fec = new H1_FECollection(order, dim);
   }

   FiniteElementSpace fespace(&mesh, fec);

   BilinearForm k_ea(&fespace);
   BilinearForm k_fa(&fespace);

   ConstantCoefficient one(1.0);
   VectorFunctionCoefficient vel_coeff(dim, velocity_function);

   if (pb==0)// Mass
   {
      k_fa.AddDomainIntegrator(new MassIntegrator(one));
      k_ea.AddDomainIntegrator(new MassIntegrator(one));
   }
   else if(pb==1)// Convection
   {
      AddConvectionIntegrators(k_fa, vel_coeff, dg);
      AddConvectionIntegrators(k_ea, vel_coeff, dg);
   }
   else if(pb==2)// Diffusion
   {
      k_fa.AddDomainIntegrator(new DiffusionIntegrator(one));
      k_ea.AddDomainIntegrator(new DiffusionIntegrator(one));
   }

   k_fa.Assemble();
   k_fa.Finalize();

   k_ea.SetAssemblyLevel(AssemblyLevel::ELEMENT);
   k_ea.Assemble();

   GridFunction x(&fespace), y_fa(&fespace), y_ea(&fespace);

   x.Randomize(1);

   k_fa.Mult(x,y_fa);
   k_ea.Mult(x,y_ea);

   y_ea -= y_fa;

   REQUIRE(y_ea.Norml2() < 1.e-12);

   delete fec;
}

//Basic unit test for convection
TEST_CASE("Element Assembly", "[ElementAssembly]")
{
   for(int pb : {0, 1, 2})
   {
      for (bool dg : {true, false})
      {
         SECTION("2D")
         {
            for (int order : {2, 3, 4})
            {
               test_ea(Mesh("../../data/periodic-square.mesh", 1, 1), order, dg, pb);
               test_ea(Mesh("../../data/periodic-hexagon.mesh", 1, 1), order, dg, pb);
               test_ea(Mesh("../../data/star-q3.mesh", 1, 1), order, dg, pb);
            }
         }

         SECTION("3D")
         {
            int order = 2;
            test_ea(Mesh("../../data/periodic-cube.mesh", 1, 1), order, dg, pb);
            test_ea(Mesh("../../data/fichera-q3.mesh", 1, 1), order, dg, pb);
         }
      }

      // Test AMR cases (DG not implemented)
      SECTION("AMR 2D")
      {
         for (int order : {2, 3, 4})
         {
            test_ea(Mesh("../../data/amr-quad.mesh", 1, 1), order, false, 0);
         }
      }
      SECTION("AMR 3D")
      {
         int order = 2;
         test_ea(Mesh("../../data/fichera-amr.mesh", 1, 1), order, false, 0);
      }
   }
}//test case

}// namespace pa_kernels
<commit_msg>make style<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "catch.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

namespace ea_kernels
{

void velocity_function(const Vector &x, Vector &v)
{
   int dim = x.Size();
   switch (dim)
   {
      case 1: v(0) = 1.0; break;
      case 2: v(0) = x(1); v(1) = -x(0); break;
      case 3: v(0) = x(1); v(1) = -x(0); v(2) = x(0); break;
   }
}

void AddConvectionIntegrators(BilinearForm &k, VectorCoefficient &velocity,
                              bool dg)
{
   k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));

   if (dg)
   {
      k.AddInteriorFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
      k.AddBdrFaceIntegrator(
         new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5)));
   }
}

void test_ea(Mesh &&mesh, int order, bool dg, const int pb)
{
   mesh.EnsureNodes();
   mesh.SetCurvature(mesh.GetNodalFESpace()->GetOrder(0));
   int dim = mesh.Dimension();

   FiniteElementCollection *fec;
   if (dg)
   {
      fec = new L2_FECollection(order, dim, BasisType::GaussLobatto);
   }
   else
   {
      fec = new H1_FECollection(order, dim);
   }

   FiniteElementSpace fespace(&mesh, fec);

   BilinearForm k_ea(&fespace);
   BilinearForm k_fa(&fespace);

   ConstantCoefficient one(1.0);
   VectorFunctionCoefficient vel_coeff(dim, velocity_function);

   if (pb==0) // Mass
   {
      k_fa.AddDomainIntegrator(new MassIntegrator(one));
      k_ea.AddDomainIntegrator(new MassIntegrator(one));
   }
   else if(pb==1) // Convection
   {
      AddConvectionIntegrators(k_fa, vel_coeff, dg);
      AddConvectionIntegrators(k_ea, vel_coeff, dg);
   }
   else if(pb==2) // Diffusion
   {
      k_fa.AddDomainIntegrator(new DiffusionIntegrator(one));
      k_ea.AddDomainIntegrator(new DiffusionIntegrator(one));
   }

   k_fa.Assemble();
   k_fa.Finalize();

   k_ea.SetAssemblyLevel(AssemblyLevel::ELEMENT);
   k_ea.Assemble();

   GridFunction x(&fespace), y_fa(&fespace), y_ea(&fespace);

   x.Randomize(1);

   k_fa.Mult(x,y_fa);
   k_ea.Mult(x,y_ea);

   y_ea -= y_fa;

   REQUIRE(y_ea.Norml2() < 1.e-12);

   delete fec;
}

//Basic unit test for convection
TEST_CASE("Element Assembly", "[ElementAssembly]")
{
   for (int pb : {0, 1, 2})
   {
      for (bool dg : {true, false})
      {
         SECTION("2D")
         {
            for (int order : {2, 3, 4})
            {
               test_ea(Mesh("../../data/periodic-square.mesh", 1, 1), order, dg, pb);
               test_ea(Mesh("../../data/periodic-hexagon.mesh", 1, 1), order, dg, pb);
               test_ea(Mesh("../../data/star-q3.mesh", 1, 1), order, dg, pb);
            }
         }

         SECTION("3D")
         {
            int order = 2;
            test_ea(Mesh("../../data/periodic-cube.mesh", 1, 1), order, dg, pb);
            test_ea(Mesh("../../data/fichera-q3.mesh", 1, 1), order, dg, pb);
         }
      }

      // Test AMR cases (DG not implemented)
      SECTION("AMR 2D")
      {
         for (int order : {2, 3, 4})
         {
            test_ea(Mesh("../../data/amr-quad.mesh", 1, 1), order, false, 0);
         }
      }
      SECTION("AMR 3D")
      {
         int order = 2;
         test_ea(Mesh("../../data/fichera-amr.mesh", 1, 1), order, false, 0);
      }
   }
}//test case

}// namespace pa_kernels
<|endoftext|>