<commit_before>/*
 *
 * StellarLikeBlockchainExplorerAccountSynchronizer.cpp
 * ledger-core
 *
 * Created by Pierre Pollastri on 10/07/2019.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2019 Ledger
 *
 * 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 "StellarLikeBlockchainExplorerAccountSynchronizer.hpp"

#include <common/AccountHelper.hpp>
#include <wallet/stellar/StellarLikeAccount.hpp>

/**
 * Current version of the synchronization. Please keep this field up to date to ensure that we have proper migration
 * mechanism if the synchronizer needs to save more data in its state in the future (or modify current value). This
 * version allow smooth migration.
 */
static const auto SYNCHRONIZATION_ALGORITHM_VERSION = 1;

namespace ledger {
    namespace core {

        StellarLikeBlockchainExplorerAccountSynchronizer::StellarLikeBlockchainExplorerAccountSynchronizer(
                const std::shared_ptr<WalletPool> &pool,
                const std::shared_ptr<StellarLikeBlockchainExplorer> &explorer) :
                DedicatedContext(pool->getDispatcher()->getSerialExecutionContext("stellar_like_account_synchronizer")),
                _explorer(explorer),
                _database(pool->getDatabaseSessionPool()) {

        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::reset(const std::shared_ptr<StellarLikeAccount> &account,
                                                                     const std::chrono::system_clock::time_point &toDate) {
            account->getInternalPreferences()->getSubPreferences("StellarLikeBlockchainExplorerAccountSynchronizer")->editor()->clear();
        }

        std::shared_ptr<ProgressNotifier<BlockchainExplorerAccountSynchronizationResult>> StellarLikeBlockchainExplorerAccountSynchronizer::synchronize(
                const std::shared_ptr<StellarLikeAccount> &account) {
            if (_notifier != nullptr) {
                return _notifier;
            }
            _notifier = std::make_shared<ProgressNotifier<BlockchainExplorerAccountSynchronizationResult>>();
            synchronizeAccount(account);
            return _notifier;
        }

        bool StellarLikeBlockchainExplorerAccountSynchronizer::isSynchronizing() const {
            return _notifier != nullptr;
        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::synchronizeAccount(const std::shared_ptr<StellarLikeAccount> &account) {
            auto self = shared_from_this();
            auto preferences = account->getInternalPreferences()->getSubPreferences("StellarLikeBlockchainExplorerAccountSynchronizer");
            auto state = preferences
                ->template getObject<StellarLikeBlockchainExplorerAccountSynchronizer::SavedState>("state")
                // provide default state if none exists yet
                .getValueOr(SavedState{});

            synchronizeAccount(account, state);
        }

        void
        StellarLikeBlockchainExplorerAccountSynchronizer::synchronizeAccount(const std::shared_ptr<StellarLikeAccount>& account,
                                                                             StellarLikeBlockchainExplorerAccountSynchronizer::SavedState &state) {
            auto address = account->getKeychain()->getAddress()->toString();
            auto self = shared_from_this();

            _explorer->getAccount(address)
                .onComplete(account->getContext(), [self, account, state] (const Try<std::shared_ptr<stellar::Account>>& accountInfo) mutable {
                   if (accountInfo.isFailure() && accountInfo.getFailure().getErrorCode() == api::ErrorCode::ACCOUNT_NOT_FOUND) {
                        self->endSynchronization(account, state);
                    } else if (accountInfo.isFailure()) {
                        self->failSynchronization(accountInfo.getFailure());
                    } else {
                        soci::session sql(self->_database->getPool());
                        account->updateAccountInfo(sql, *accountInfo.getValue());
                        self->synchronizeTransactions(account, state);
                    }
                });
        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::synchronizeTransactions(
                const std::shared_ptr<StellarLikeAccount> &account,
                StellarLikeBlockchainExplorerAccountSynchronizer::SavedState &state) {
            auto address = account->getKeychain()->getAddress()->toString();
            auto self = shared_from_this();
           fmt::print("Current paging token: {}\n", state.transactionPagingToken.getValueOr("no paging token"));
            _explorer->getTransactions(address, state.transactionPagingToken)
                .onComplete(account->getContext(), [self, account, state] (const Try<stellar::TransactionVector>& txs) mutable {
                if (txs.isFailure()) {
                    self->failSynchronization(txs.getFailure());
                } else {
                    {
                        soci::session sql(self->_database->getPool());
                        soci::transaction tr(sql);

                        for (const auto &tx : txs.getValue()) {
                            account->logger()->debug("XLM transaction hash: {}, paging_token: {}", tx->hash, tx->pagingToken);
                            auto const flag = account->putTransaction(sql, *tx);

                            if (::ledger::core::account::isInsertedOperation(flag)) {
                                ++state.insertedOperations;
                            }

                            state.lastBlockHeight = std::max(state.lastBlockHeight, tx->ledger);
                        }
                        tr.commit();
                    }
                    if (!txs.getValue().empty()) {
                        state.transactionPagingToken = txs.getValue().back()->pagingToken;
                        fmt::print("Paging token for next round: {}\n", state.transactionPagingToken.getValueOr("no paging token"));
                        {
                            auto preferences = account->getInternalPreferences()->getSubPreferences("StellarLikeBlockchainExplorerAccountSynchronizer");
                            preferences->editor()->putObject("state", state)->commit();
                        }

                        self->synchronizeTransactions(account, state);
                    } else {
                        self->endSynchronization(account, state);
                    }
                }
            });
        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::endSynchronization(
                const std::shared_ptr<StellarLikeAccount>& account,
                const StellarLikeBlockchainExplorerAccountSynchronizer::SavedState &state) {
            BlockchainExplorerAccountSynchronizationResult result;

            soci::session sql(account->getWallet()->getDatabase()->getPool());
            result.lastBlockHeight = BlockDatabaseHelper::getLastBlock(sql,
                                                                               account->getWallet()->getCurrency().name)
                                                                                .template map<uint64_t>([] (const Block& block) {
                return block.height;
            }).getValueOr(0);

            result.newOperations = state.insertedOperations;

            _notifier->success(result);
            _notifier = nullptr;
        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::failSynchronization(const Exception &ex) {
            _notifier->failure(ex);
            _notifier = nullptr;
        }
    }
}
<commit_msg>Emit env at the end of batch insertion for XLM<commit_after>/*
 *
 * StellarLikeBlockchainExplorerAccountSynchronizer.cpp
 * ledger-core
 *
 * Created by Pierre Pollastri on 10/07/2019.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2019 Ledger
 *
 * 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 "StellarLikeBlockchainExplorerAccountSynchronizer.hpp"

#include <common/AccountHelper.hpp>
#include <wallet/stellar/StellarLikeAccount.hpp>

/**
 * Current version of the synchronization. Please keep this field up to date to ensure that we have proper migration
 * mechanism if the synchronizer needs to save more data in its state in the future (or modify current value). This
 * version allow smooth migration.
 */
static const auto SYNCHRONIZATION_ALGORITHM_VERSION = 1;

namespace ledger {
    namespace core {

        StellarLikeBlockchainExplorerAccountSynchronizer::StellarLikeBlockchainExplorerAccountSynchronizer(
                const std::shared_ptr<WalletPool> &pool,
                const std::shared_ptr<StellarLikeBlockchainExplorer> &explorer) :
                DedicatedContext(pool->getDispatcher()->getSerialExecutionContext("stellar_like_account_synchronizer")),
                _explorer(explorer),
                _database(pool->getDatabaseSessionPool()) {

        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::reset(const std::shared_ptr<StellarLikeAccount> &account,
                                                                     const std::chrono::system_clock::time_point &toDate) {
            account->getInternalPreferences()->getSubPreferences("StellarLikeBlockchainExplorerAccountSynchronizer")->editor()->clear();
        }

        std::shared_ptr<ProgressNotifier<BlockchainExplorerAccountSynchronizationResult>> StellarLikeBlockchainExplorerAccountSynchronizer::synchronize(
                const std::shared_ptr<StellarLikeAccount> &account) {
            if (_notifier != nullptr) {
                return _notifier;
            }
            _notifier = std::make_shared<ProgressNotifier<BlockchainExplorerAccountSynchronizationResult>>();
            synchronizeAccount(account);
            return _notifier;
        }

        bool StellarLikeBlockchainExplorerAccountSynchronizer::isSynchronizing() const {
            return _notifier != nullptr;
        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::synchronizeAccount(const std::shared_ptr<StellarLikeAccount> &account) {
            auto self = shared_from_this();
            auto preferences = account->getInternalPreferences()->getSubPreferences("StellarLikeBlockchainExplorerAccountSynchronizer");
            auto state = preferences
                ->template getObject<StellarLikeBlockchainExplorerAccountSynchronizer::SavedState>("state")
                // provide default state if none exists yet
                .getValueOr(SavedState{});

            synchronizeAccount(account, state);
        }

        void
        StellarLikeBlockchainExplorerAccountSynchronizer::synchronizeAccount(const std::shared_ptr<StellarLikeAccount>& account,
                                                                             StellarLikeBlockchainExplorerAccountSynchronizer::SavedState &state) {
            auto address = account->getKeychain()->getAddress()->toString();
            auto self = shared_from_this();

            _explorer->getAccount(address)
                .onComplete(account->getContext(), [self, account, state] (const Try<std::shared_ptr<stellar::Account>>& accountInfo) mutable {
                   if (accountInfo.isFailure() && accountInfo.getFailure().getErrorCode() == api::ErrorCode::ACCOUNT_NOT_FOUND) {
                        self->endSynchronization(account, state);
                    } else if (accountInfo.isFailure()) {
                        self->failSynchronization(accountInfo.getFailure());
                    } else {
                        soci::session sql(self->_database->getPool());
                        account->updateAccountInfo(sql, *accountInfo.getValue());
                        self->synchronizeTransactions(account, state);
                    }
                });
        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::synchronizeTransactions(
                const std::shared_ptr<StellarLikeAccount> &account,
                StellarLikeBlockchainExplorerAccountSynchronizer::SavedState &state) {
            auto address = account->getKeychain()->getAddress()->toString();
            auto self = shared_from_this();
           fmt::print("Current paging token: {}\n", state.transactionPagingToken.getValueOr("no paging token"));
            _explorer->getTransactions(address, state.transactionPagingToken)
                .onComplete(account->getContext(), [self, account, state] (const Try<stellar::TransactionVector>& txs) mutable {
                if (txs.isFailure()) {
                    self->failSynchronization(txs.getFailure());
                } else {
                    {
                        for (const auto &tx : txs.getValue()) {
                            soci::session sql(self->_database->getPool());
                            soci::transaction tr(sql);
                            account->logger()->debug("XLM transaction hash: {}, paging_token: {}", tx->hash, tx->pagingToken);
                            auto const flag = account->putTransaction(sql, *tx);

                            if (::ledger::core::account::isInsertedOperation(flag)) {
                                ++state.insertedOperations;
                            }
                            tr.commit();
                            state.lastBlockHeight = std::max(state.lastBlockHeight, tx->ledger);
                        }
                    }
                    account->emitEventsNow();
                    if (!txs.getValue().empty()) {
                        state.transactionPagingToken = txs.getValue().back()->pagingToken;
                        fmt::print("Paging token for next round: {}\n", state.transactionPagingToken.getValueOr("no paging token"));
                        {
                            auto preferences = account->getInternalPreferences()->getSubPreferences("StellarLikeBlockchainExplorerAccountSynchronizer");
                            preferences->editor()->putObject("state", state)->commit();
                        }

                        self->synchronizeTransactions(account, state);
                    } else {
                        self->endSynchronization(account, state);
                    }
                }
            });
        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::endSynchronization(
                const std::shared_ptr<StellarLikeAccount>& account,
                const StellarLikeBlockchainExplorerAccountSynchronizer::SavedState &state) {
            BlockchainExplorerAccountSynchronizationResult result;

            soci::session sql(account->getWallet()->getDatabase()->getPool());
            result.lastBlockHeight = BlockDatabaseHelper::getLastBlock(sql,
                                                                               account->getWallet()->getCurrency().name)
                                                                                .template map<uint64_t>([] (const Block& block) {
                return block.height;
            }).getValueOr(0);

            result.newOperations = state.insertedOperations;

            _notifier->success(result);
            _notifier = nullptr;
        }

        void StellarLikeBlockchainExplorerAccountSynchronizer::failSynchronization(const Exception &ex) {
            _notifier->failure(ex);
            _notifier = nullptr;
        }
    }
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Copyright (c) 2017 Josef Adamsson
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2017 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/crystalvisualization/processors/coordinatereader.h>
#include <modules/hdf5/datastructures/hdf5handle.h>
#include <modules/hdf5/datastructures/hdf5path.h>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo CoordinateReader::processorInfo_{
    "envision.CoordinateReader",      // Class identifier
    "Coordinate Reader",                // Display name
    "Crystal",                          // Category
    CodeState::Experimental,  // Code state
    Tags::None,               // Tags
};
const ProcessorInfo CoordinateReader::getProcessorInfo() const {
    return processorInfo_;
}

CoordinateReader::CoordinateReader()
    : Processor()
    , outport_("outport")
    , inport_("inport")

    // New property for animations
    , timestep_("timestep", "Time step", false)
    , path_("path", "Path", "", InvalidationLevel::InvalidOutput, PropertySemantics::Default) {

    addPort(outport_);
    addPort(inport_);

    // New property for animations
    addProperty(timestep_);
    addProperty(path_);
}

void CoordinateReader::process() {
    const auto h5path = hdf5::Path(path_.get());
    const auto data = inport_.getData();
    auto vecptr = std::make_shared<std::vector<vec3>>(data->getVectorOfVec3AtPath<float>(h5path));
    outport_.setData(vecptr);
}

} // namespace
<commit_msg>Ny branch för coordreader<commit_after>/*********************************************************************************
 *
 * Copyright (c) 2017 Josef Adamsson
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2017 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/crystalvisualization/processors/coordinatereader.h>
#include <modules/hdf5/datastructures/hdf5handle.h>
#include <modules/hdf5/datastructures/hdf5path.h>

namespace inviwo {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo CoordinateReader::processorInfo_{
    "envision.CoordinateReader",      // Class identifier
    "Coordinate Reader",                // Display name
    "Crystal",                          // Category
    CodeState::Experimental,  // Code state
    Tags::None,               // Tags
};
const ProcessorInfo CoordinateReader::getProcessorInfo() const {
    return processorInfo_;
}

CoordinateReader::CoordinateReader()
    : Processor()
    , outport_("outport")
    , inport_("inport")

    // New property for animations
    , timestep_("timestep", "Time step", false)
    , path_("path", "Path", "", InvalidationLevel::InvalidOutput, PropertySemantics::Default) {

    addPort(outport_);
    addPort(inport_);

    // New property for animations
    addProperty(timestep_);
    addProperty(path_);
}

void CoordinateReader::process() {
    const auto h5path = hdf5::Path(path_.get());
    const auto data = inport_.getData();

/*
if ibrion = 0
  timeh5 = h5path.split('/')
else

*/

    auto vecptr = std::make_shared<std::vector<vec3>>(data->getVectorOfVec3AtPath<float>(h5path));
    outport_.setData(vecptr);
}

} // namespace
<|endoftext|>


<commit_before>/*
 *  caosVM_flow.cpp
 *  openc2e
 *
 *  Created by Alyssa Milburn on Sun May 30 2004.
 *  Copyright (c) 2004 Alyssa Milburn. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 */

#include "caosVM.h"
#include <iostream>
#include "openc2e.h"
#include "World.h" // enum
#include <cmath>   // sqrt
#include <sstream>
#include "AgentHelpers.h"

/**
 DOIF (command) condition (condition)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 Part of a DOIF/ELIF/ELSE/ENDI block. Jumps to the next part of the block if condition is false,
 otherwise continues executing the script.
*/
void caosVM::c_DOIF() {
	// handled elsewhere
}

/**
 ELIF (command) condition (condition)
 %pragma variants all
 %status maybe
 %cost c1,c2 0

 Part of a DOIF/ELIF/ELSE/ENDI block. If none of the previous DOIF/ELIF conditions have been true, and condition evaluates to true, then the code in the ELIF block is executed.
 If found outside a DOIF block, it is equivalent to a DOIF. If you take advantage of this behavior, fuzzie is of the opinion that you should be shot.
*/
void caosVM::c_ELIF() {
	// handled elsewhere
}

/**
 ELSE (command)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 Part of a DOIF/ELIF/ELSE/ENDI block. If ELSE is present, it is jumped to when none of the previous DOIF/ELIF conditions are true.
*/
void caosVM::c_ELSE() {
	// handled elsewhere
}

/**
 ENDI (command)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 The end of a DOIF/ELIF/ELSE/ENDI block.
*/
void caosVM::c_ENDI() {
	// TODO: cost in c2e?
}

/**
 REPS (command) reps (integer)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 The start of a REPS...REPE loop. The body of the loop will be executed (reps) times.
*/
void caosVM::c_REPS() {
	// Our expression parameter might push on a value that's a pointer
	// (or otherwise not an integer); deal with it

	VM_PARAM_INTEGER(n);
	result.setInt(n+1); // we'll visit the DECJNZ first to handle 0 etc
}

/**
 REPE (command)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 The end of a REPS...REPE loop.
*/
void caosVM::c_REPE() {
	// handled elsewhere
}

/**
 LOOP (command)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 The start of a LOOP...EVER or LOOP...UNTL loop.
*/
void caosVM::c_LOOP() {
	// handled elsewhere
}

/**
 EVER (command)
 %status maybe
 %pragma variants c1 c2 cv c3

 Jumps back to the matching LOOP, no matter what.
*/
void caosVM::c_EVER() {
	// handled elsewhere
}

/**
 UNTL (command) condition (condition)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 Jumps back to the matching LOOP unless the condition evaluates to true.
*/
void caosVM::c_UNTL() {
	// handled elsewhere
}

/**
 GSUB (command) label (label)
 %pragma retc -1
 %status maybe
 %pragma variants c1 c2 cv c3

 Jumps to a subroutine defined by SUBR with label (label).
*/
void caosVM::c_GSUB() {
	// handled elsewhere
}

/**
 SUBR (command) label (label)
 %status maybe
 %pragma variants c1 c2 cv c3

 Defines the start of a subroute to be called with GSUB, with label (label).
 If the command is encountered during execution, it acts like a STOP.
*/
void caosVM::c_SUBR() {
	// handled elsewhere
}

/**
 RETN (command)
 %pragma retc -1
 %status maybe
 %pragma variants c1 c2 cv c3

 Returns from a subroutine called with GSUB.
*/
void caosVM::c_RETN() {
	if (callStack.empty())
		throw creaturesException("RETN with an empty callstack");
	nip = callStack.back().nip;
	callStack.back().valueStack.swap(valueStack);
	callStack.back().valueStack.clear(); // just in case
	callStack.pop_back();
}

/**
 NEXT (command)
 %status maybe
 %pragma variants all
 %cost c1,c2 0

 The end of an ENUM...NEXT loop.
*/
void caosVM::c_NEXT() {
	targ = owner;
}

/**
 ENUM (command) family (integer) genus (integer) species (integer)
 %status maybe
 %pragma retc -1
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 Loops through all agents with the given classifier.  0 on any field is a
 wildcard. The loop body is terminated by a NEXT.
*/
void caosVM::c_ENUM() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_INTEGER(species) caos_assert(species >= 0); caos_assert(species <= 65535);
	VM_PARAM_INTEGER(genus) caos_assert(genus >= 0); caos_assert(genus <= 255);
	VM_PARAM_INTEGER(family) caos_assert(family >= 0); caos_assert(family <= 255);

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);

	for (std::list<boost::shared_ptr<Agent> >::iterator i
			= world.agents.begin(); i != world.agents.end(); i++) {
		boost::shared_ptr<Agent> a = (*i);
		if (!a) continue;
		if (species && species != a->species) continue;
		if (genus && genus != a->genus) continue;
		if (family && family != a->family) continue;

		caosVar v; v.setAgent(a);
		valueStack.push_back(v);
	}
}

/**
 ESEE (command) family (integer) genus (integer) species (integer)
 %status maybe
 %pragma retc -1
 %pragma variants c2 cv c3

 Simular to ENUM, but iterates through agents visible to OWNR, or visible to TARG in an install script.
 An agent can be seen if it is within the range set by RNGE, and is visible (this includes the PERM value
 of walls that lie between them, and, if the agent is a Creature, it not having the 'invisible' attribute).
*/
void caosVM::c_ESEE() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_INTEGER(species) caos_assert(species >= 0); caos_assert(species <= 65535);
	VM_PARAM_INTEGER(genus) caos_assert(genus >= 0); caos_assert(genus <= 255);
	VM_PARAM_INTEGER(family) caos_assert(family >= 0); caos_assert(family <= 255);

	Agent *seeing;
	if (owner) seeing = owner; else seeing = targ;
	valid_agent(seeing);

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);

	std::vector<boost::shared_ptr<Agent> > agents = getVisibleList(seeing, family, genus, species);
	for (std::vector<boost::shared_ptr<Agent> >::iterator i = agents.begin(); i != agents.end(); i++) {
		caosVar v; v.setAgent(*i);
		valueStack.push_back(v);
	}
}

bool agentsTouching(Agent *first, Agent *second); // caosVM_agent.cpp

/**
 ETCH (command) family (integer) genus (integer) species (integer)
 %pragma retc -1
 %status maybe
 %pragma variants c2 cv c3

 Similar to ENUM, but iterates through the agents OWNR is touching, or TARG is touching in an install script.
*/
void caosVM::c_ETCH() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_INTEGER(species) caos_assert(species >= 0); caos_assert(species <= 65535);
	VM_PARAM_INTEGER(genus) caos_assert(genus >= 0); caos_assert(genus <= 255);
	VM_PARAM_INTEGER(family) caos_assert(family >= 0); caos_assert(family <= 255);

	Agent *touching;
	if (owner) touching = owner; else touching = targ;
	valid_agent(touching);

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);

	for (std::list<boost::shared_ptr<Agent> >::iterator i
			= world.agents.begin(); i != world.agents.end(); i++) {
		boost::shared_ptr<Agent> a = (*i);
		if (!a) continue;
		if (species && species != a->species) continue;
		if (genus && genus != a->genus) continue;
		if (family && family != a->family) continue;
		if (a.get() == touching) continue;

		if (agentsTouching(a.get(), touching)) {
			caosVar v; v.setAgent(a);
			valueStack.push_back(v);
		}
	}
}

/**
 EPAS (command) family (integer) genus (integer) species (integer)
 %pragma retc -1
 %status stub

 Similar to ENUM, but iterates through the OWNR vehicle's passengers.
*/
void caosVM::c_EPAS() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_INTEGER(species) caos_assert(species >= 0); caos_assert(species <= 65535);
	VM_PARAM_INTEGER(genus) caos_assert(genus >= 0); caos_assert(genus <= 255);
	VM_PARAM_INTEGER(family) caos_assert(family >= 0); caos_assert(family <= 255);

	// TODO: should probably implement this (ESEE)

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);
}

/**
 ECON (command) agent (agent)
 %pragma retc -1
 %status stub

 Loops through all the agents in the connective system containing the given agent.
*/
void caosVM::c_ECON() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_VALIDAGENT(agent)

	// TODO: should probably implement this (ESEE)

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);
}

/**
 CALL (command) script_no (integer) p1 (any) p2 (any)
 %status maybe
 %pragma variants c2 cv c3

 Calls script_no on OWNR, then waits for it to return. The invoked script
 will inherit the caller's INST setting, but any changes it makes to it will
 be reversed once it returns - so eg if you call a script when in INST mode,
 it calls OVER and returns, you'll still be in INST.

 Script variables (VAxx) will not be preserved - you'll have to use OVxx
 for any parameters.
 */
void caosVM::c_CALL() {
	VM_PARAM_VALUE(p2)
	VM_PARAM_VALUE(p1)
	VM_PARAM_INTEGER(script_no)

	valid_agent(owner);
	caos_assert(script_no >= 0 && script_no < 65536);

	shared_ptr<script> s = owner->findScript(script_no);
	if (!s) return;
	caosVM *newvm = world.getVM(owner);
	newvm->trace = trace;

	ensure(newvm->fireScript(s, false));
	newvm->inst = inst;
	newvm->_p_[0] = p1;
	newvm->_p_[1] = p2;
	owner->pushVM(newvm);
	stop_loop = true;
}

/**
 CAOS (string) inline (integer) state_trans (integer) p1 (anything) p2 (anything) commands (string) throws (integer) catches (integer) report (variable)
 %status maybe

 Runs commands as caos code immediately. If inline, copy _IT_ VAxx TARG OWNR, etc. If state_trans, copy FROM and
 OWNR.  If an error occurs, it catches it and stuffs it in the report. (XXX: non-conforming)
*/

// XXX: exception catching is very broken right now

void caosVM::v_CAOS() {
	// XXX: capture output
	VM_PARAM_VARIABLE(report)
	VM_PARAM_INTEGER(catches)
	VM_PARAM_INTEGER(throws)
	VM_PARAM_STRING(commands)
	VM_PARAM_VALUE(p2)
	VM_PARAM_VALUE(p1)
	VM_PARAM_INTEGER(state_trans)
	VM_PARAM_INTEGER(inl)

	caosVM *sub = world.getVM(NULL);
	sub->resetCore();
	if (inl) {
		for (int i = 0; i < 100; i++)
			sub->var[i] = var[i];
		sub->targ = targ;
		sub->_it_ = _it_;
		sub->part = part;
		sub->owner = owner;
		// sub->from = from;
	}
	if (state_trans) {
		sub->owner = owner;
		// sub->from = from;
	}
	sub->_p_[0] = p1;
	sub->_p_[1] = p2;
	try {
		std::istringstream iss(commands);
		std::ostringstream oss;
		caosScript s("c3", "CAOS command"); // XXX: variant
		s.parse(iss);
		s.installScripts();
		sub->outputstream = &oss;
		sub->runEntirely(s.installer);
		sub->outputstream = &std::cout;
		result.setString(oss.str());
	} catch (std::exception &e) {
		sub->outputstream = &std::cout;
		if (!throws || catches) {
			report->setString(e.what());
			result.setString("###");
		} else {
			world.freeVM(sub);
			throw;
		}
	}
	world.freeVM(sub);
}

/* vim: set noet: */
<commit_msg>implement EPAS<commit_after>/*
 *  caosVM_flow.cpp
 *  openc2e
 *
 *  Created by Alyssa Milburn on Sun May 30 2004.
 *  Copyright (c) 2004 Alyssa Milburn. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 */

#include "caosVM.h"
#include <iostream>
#include "openc2e.h"
#include "World.h" // enum
#include <cmath>   // sqrt
#include <sstream>
#include "AgentHelpers.h"
#include "Vehicle.h" // EPAS

/**
 DOIF (command) condition (condition)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 Part of a DOIF/ELIF/ELSE/ENDI block. Jumps to the next part of the block if condition is false,
 otherwise continues executing the script.
*/
void caosVM::c_DOIF() {
	// handled elsewhere
}

/**
 ELIF (command) condition (condition)
 %pragma variants all
 %status maybe
 %cost c1,c2 0

 Part of a DOIF/ELIF/ELSE/ENDI block. If none of the previous DOIF/ELIF conditions have been true, and condition evaluates to true, then the code in the ELIF block is executed.
 If found outside a DOIF block, it is equivalent to a DOIF. If you take advantage of this behavior, fuzzie is of the opinion that you should be shot.
*/
void caosVM::c_ELIF() {
	// handled elsewhere
}

/**
 ELSE (command)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 Part of a DOIF/ELIF/ELSE/ENDI block. If ELSE is present, it is jumped to when none of the previous DOIF/ELIF conditions are true.
*/
void caosVM::c_ELSE() {
	// handled elsewhere
}

/**
 ENDI (command)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 The end of a DOIF/ELIF/ELSE/ENDI block.
*/
void caosVM::c_ENDI() {
	// TODO: cost in c2e?
}

/**
 REPS (command) reps (integer)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 The start of a REPS...REPE loop. The body of the loop will be executed (reps) times.
*/
void caosVM::c_REPS() {
	// Our expression parameter might push on a value that's a pointer
	// (or otherwise not an integer); deal with it

	VM_PARAM_INTEGER(n);
	result.setInt(n+1); // we'll visit the DECJNZ first to handle 0 etc
}

/**
 REPE (command)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 The end of a REPS...REPE loop.
*/
void caosVM::c_REPE() {
	// handled elsewhere
}

/**
 LOOP (command)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 The start of a LOOP...EVER or LOOP...UNTL loop.
*/
void caosVM::c_LOOP() {
	// handled elsewhere
}

/**
 EVER (command)
 %status maybe
 %pragma variants c1 c2 cv c3

 Jumps back to the matching LOOP, no matter what.
*/
void caosVM::c_EVER() {
	// handled elsewhere
}

/**
 UNTL (command) condition (condition)
 %status maybe
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 Jumps back to the matching LOOP unless the condition evaluates to true.
*/
void caosVM::c_UNTL() {
	// handled elsewhere
}

/**
 GSUB (command) label (label)
 %pragma retc -1
 %status maybe
 %pragma variants c1 c2 cv c3

 Jumps to a subroutine defined by SUBR with label (label).
*/
void caosVM::c_GSUB() {
	// handled elsewhere
}

/**
 SUBR (command) label (label)
 %status maybe
 %pragma variants c1 c2 cv c3

 Defines the start of a subroute to be called with GSUB, with label (label).
 If the command is encountered during execution, it acts like a STOP.
*/
void caosVM::c_SUBR() {
	// handled elsewhere
}

/**
 RETN (command)
 %pragma retc -1
 %status maybe
 %pragma variants c1 c2 cv c3

 Returns from a subroutine called with GSUB.
*/
void caosVM::c_RETN() {
	if (callStack.empty())
		throw creaturesException("RETN with an empty callstack");
	nip = callStack.back().nip;
	callStack.back().valueStack.swap(valueStack);
	callStack.back().valueStack.clear(); // just in case
	callStack.pop_back();
}

/**
 NEXT (command)
 %status maybe
 %pragma variants all
 %cost c1,c2 0

 The end of an ENUM...NEXT loop.
*/
void caosVM::c_NEXT() {
	targ = owner;
}

/**
 ENUM (command) family (integer) genus (integer) species (integer)
 %status maybe
 %pragma retc -1
 %pragma variants c1 c2 cv c3
 %cost c1,c2 0

 Loops through all agents with the given classifier.  0 on any field is a
 wildcard. The loop body is terminated by a NEXT.
*/
void caosVM::c_ENUM() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_INTEGER(species) caos_assert(species >= 0); caos_assert(species <= 65535);
	VM_PARAM_INTEGER(genus) caos_assert(genus >= 0); caos_assert(genus <= 255);
	VM_PARAM_INTEGER(family) caos_assert(family >= 0); caos_assert(family <= 255);

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);

	for (std::list<boost::shared_ptr<Agent> >::iterator i
			= world.agents.begin(); i != world.agents.end(); i++) {
		boost::shared_ptr<Agent> a = (*i);
		if (!a) continue;
		if (species && species != a->species) continue;
		if (genus && genus != a->genus) continue;
		if (family && family != a->family) continue;

		caosVar v; v.setAgent(a);
		valueStack.push_back(v);
	}
}

/**
 ESEE (command) family (integer) genus (integer) species (integer)
 %status maybe
 %pragma retc -1
 %pragma variants c2 cv c3

 Simular to ENUM, but iterates through agents visible to OWNR, or visible to TARG in an install script.
 An agent can be seen if it is within the range set by RNGE, and is visible (this includes the PERM value
 of walls that lie between them, and, if the agent is a Creature, it not having the 'invisible' attribute).
*/
void caosVM::c_ESEE() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_INTEGER(species) caos_assert(species >= 0); caos_assert(species <= 65535);
	VM_PARAM_INTEGER(genus) caos_assert(genus >= 0); caos_assert(genus <= 255);
	VM_PARAM_INTEGER(family) caos_assert(family >= 0); caos_assert(family <= 255);

	Agent *seeing;
	if (owner) seeing = owner; else seeing = targ;
	valid_agent(seeing);

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);

	std::vector<boost::shared_ptr<Agent> > agents = getVisibleList(seeing, family, genus, species);
	for (std::vector<boost::shared_ptr<Agent> >::iterator i = agents.begin(); i != agents.end(); i++) {
		caosVar v; v.setAgent(*i);
		valueStack.push_back(v);
	}
}

bool agentsTouching(Agent *first, Agent *second); // caosVM_agent.cpp

/**
 ETCH (command) family (integer) genus (integer) species (integer)
 %pragma retc -1
 %status maybe
 %pragma variants c2 cv c3

 Similar to ENUM, but iterates through the agents OWNR is touching, or TARG is touching in an install script.
*/
void caosVM::c_ETCH() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_INTEGER(species) caos_assert(species >= 0); caos_assert(species <= 65535);
	VM_PARAM_INTEGER(genus) caos_assert(genus >= 0); caos_assert(genus <= 255);
	VM_PARAM_INTEGER(family) caos_assert(family >= 0); caos_assert(family <= 255);

	Agent *touching;
	if (owner) touching = owner; else touching = targ;
	valid_agent(touching);

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);

	for (std::list<boost::shared_ptr<Agent> >::iterator i
			= world.agents.begin(); i != world.agents.end(); i++) {
		boost::shared_ptr<Agent> a = (*i);
		if (!a) continue;
		if (species && species != a->species) continue;
		if (genus && genus != a->genus) continue;
		if (family && family != a->family) continue;
		if (a.get() == touching) continue;

		if (agentsTouching(a.get(), touching)) {
			caosVar v; v.setAgent(a);
			valueStack.push_back(v);
		}
	}
}

/**
 EPAS (command) family (integer) genus (integer) species (integer)
 %pragma retc -1
 %status maybe

 Similar to ENUM, but iterates through the OWNR vehicle's passengers.
*/
void caosVM::c_EPAS() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_INTEGER(species) caos_assert(species >= 0); caos_assert(species <= 65535);
	VM_PARAM_INTEGER(genus) caos_assert(genus >= 0); caos_assert(genus <= 255);
	VM_PARAM_INTEGER(family) caos_assert(family >= 0); caos_assert(family <= 255);

	caos_assert(owner);
	Vehicle *v = dynamic_cast<Vehicle *>(owner.get());
	caos_assert(v);

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);

	for (std::vector<AgentRef>::iterator i = v->passengers.begin(); i != v->passengers.end(); i++) {
		AgentRef a = *i;
		if (!a) continue; // TODO: hrr
		if (species && species != a->species) continue;
		if (genus && genus != a->genus) continue;
		if (family && family != a->family) continue;

		caosVar v; v.setAgent(a); valueStack.push_back(v);
	}
}

/**
 ECON (command) agent (agent)
 %pragma retc -1
 %status stub

 Loops through all the agents in the connective system containing the given agent.
*/
void caosVM::c_ECON() {
	VM_VERIFY_SIZE(3)
	VM_PARAM_VALIDAGENT(agent)

	// TODO: should probably implement this (ECON)

	caosVar nullv; nullv.reset();
	valueStack.push_back(nullv);
}

/**
 CALL (command) script_no (integer) p1 (any) p2 (any)
 %status maybe
 %pragma variants c2 cv c3

 Calls script_no on OWNR, then waits for it to return. The invoked script
 will inherit the caller's INST setting, but any changes it makes to it will
 be reversed once it returns - so eg if you call a script when in INST mode,
 it calls OVER and returns, you'll still be in INST.

 Script variables (VAxx) will not be preserved - you'll have to use OVxx
 for any parameters.
 */
void caosVM::c_CALL() {
	VM_PARAM_VALUE(p2)
	VM_PARAM_VALUE(p1)
	VM_PARAM_INTEGER(script_no)

	valid_agent(owner);
	caos_assert(script_no >= 0 && script_no < 65536);

	shared_ptr<script> s = owner->findScript(script_no);
	if (!s) return;
	caosVM *newvm = world.getVM(owner);
	newvm->trace = trace;

	ensure(newvm->fireScript(s, false));
	newvm->inst = inst;
	newvm->_p_[0] = p1;
	newvm->_p_[1] = p2;
	owner->pushVM(newvm);
	stop_loop = true;
}

/**
 CAOS (string) inline (integer) state_trans (integer) p1 (anything) p2 (anything) commands (string) throws (integer) catches (integer) report (variable)
 %status maybe

 Runs commands as caos code immediately. If inline, copy _IT_ VAxx TARG OWNR, etc. If state_trans, copy FROM and
 OWNR.  If an error occurs, it catches it and stuffs it in the report. (XXX: non-conforming)
*/

// XXX: exception catching is very broken right now

void caosVM::v_CAOS() {
	// XXX: capture output
	VM_PARAM_VARIABLE(report)
	VM_PARAM_INTEGER(catches)
	VM_PARAM_INTEGER(throws)
	VM_PARAM_STRING(commands)
	VM_PARAM_VALUE(p2)
	VM_PARAM_VALUE(p1)
	VM_PARAM_INTEGER(state_trans)
	VM_PARAM_INTEGER(inl)

	caosVM *sub = world.getVM(NULL);
	sub->resetCore();
	if (inl) {
		for (int i = 0; i < 100; i++)
			sub->var[i] = var[i];
		sub->targ = targ;
		sub->_it_ = _it_;
		sub->part = part;
		sub->owner = owner;
		// sub->from = from;
	}
	if (state_trans) {
		sub->owner = owner;
		// sub->from = from;
	}
	sub->_p_[0] = p1;
	sub->_p_[1] = p2;
	try {
		std::istringstream iss(commands);
		std::ostringstream oss;
		caosScript s("c3", "CAOS command"); // XXX: variant
		s.parse(iss);
		s.installScripts();
		sub->outputstream = &oss;
		sub->runEntirely(s.installer);
		sub->outputstream = &std::cout;
		result.setString(oss.str());
	} catch (std::exception &e) {
		sub->outputstream = &std::cout;
		if (!throws || catches) {
			report->setString(e.what());
			result.setString("###");
		} else {
			world.freeVM(sub);
			throw;
		}
	}
	world.freeVM(sub);
}

/* vim: set noet: */
<|endoftext|>


<commit_before>#pragma once
#include <vector>
#include <cmath>
#include <utility>
#include <algorithm>
#include "command.hpp"
#include "tank.hpp"
#include "state.hpp"

class TankManager {
public:
  void Act();
  Tank getClosestEnemyTank(Tank tank);
  double getDistance(Tank tank1, Tank tank2);

  void aimAt(Tank shooter, Tank target);
  double getShellTravelTime(Tank tank, Tank tank2);

  double getAngle(double x , double y, double x1, double y1);
  bool isFriendinLine(Tank shooter, Tank target);

  std::pair<double,double> getVector(Tank tank);
  std::pair<double, double> getVector(double x, double y, double x1, double y2);

private:
};

void TankManager::Act() {
  State &state = State::Instance();

  // If we don't have any tanks yet don't act
  if(state.getPlayerTanks().empty() || state.getEnemyTanks().empty()) {
    std::cout << "we're all out of tanks" << std::endl;
    std::cout << "player tanks: " << state.getPlayerTanks().size() << std::endl;
    std::cout << "enemy tanks: " << state.getEnemyTanks().size() << std::endl;
    return;
  }

  for (auto tank : state.getPlayerTanks()) {
    if(!tank.isAlive()) {
      continue;
    }
    Tank target = getClosestEnemyTank(tank);
    aimAt(tank, target);
//    tank.Move(FWD, 1);
    if ( isFriendinLine(tank,target)) {
    }
    else {
      tank.Fire();
    }
    std::cout << "tank id: " << tank.getID() << std::endl;
  }
}

Tank TankManager::getClosestEnemyTank(Tank shooter) {
  State &state = State::Instance();
  Tank target = state.getEnemyTanks()[0];
  int i = 0;
  for (const auto &tank : state.getEnemyTanks()) {
    if (getDistance(shooter, target) > getDistance(shooter, tank)) {
      std::cout << "i found a closer tank" << std::endl;
      target = tank;
    }
  }
  return target;
}

/*void TankManager::aimAt(Tank shooter, Tank target) {
  double angle = atan2(target.gety() - shooter.gety(), target.getx() - shooter.getx());
  double turn = angle - shooter.getturret();
  if (turn > 0) {
    shooter.RotateTurret(CCW, turn);
  } else {
    shooter.RotateTurret(CW, -1 * turn);
  }
//  shooter.Fire();
}*/

void TankManager::aimAt(Tank shooter, Tank target) {
  double angle = atan2(target.gety() - shooter.gety(), target.getx() - shooter.getx());
  if(angle < 0) {
    angle = angle + (2 * M_PI);
  }
  double current = shooter.getturret();
  double amount = angle - current;
  if(amount > 0) {
    shooter.RotateTurret(CCW, amount / 2);
    shooter.Rotate(CCW, amount / 2);
  } else {
    shooter.RotateTurret(CW, -amount / 2);
    shooter.Rotate(CW, -amount / 2);
  }
}

double TankManager::getDistance(Tank tank1, Tank tank2) {
  return std::pow(tank1.getx() - tank2.getx(), 2) + std::pow(tank1.gety() - tank2.gety(), 2);
}

double TankManager::getShellTravelTime(Tank tank, Tank tank2) {
  double dist = getDistance(tank, tank2);
  return dist / 30;
}

std::pair<double,double> TankManager::getVector(Tank tank) {
  std::pair<double,double> vec;
  vec.first = cos(tank.getturret());
  vec.second = sin(tank.getturret());
  return vec;
}

std::pair<double, double> TankManager::getVector(double x, double y, double x1, double y1) {
  std::pair<double, double> vec;
  vec.first = x - x1;
  vec.second = y - y1;
  return vec;
}

double TankManager::getAngle(double x , double y, double x1, double y1) {
  double angle = atan2(x- y, x1 - y1);
  if(angle < 0) {
    angle = angle + (2 * M_PI);
  }
  return angle;
}

bool TankManager::isFriendinLine(Tank shooter, Tank target) {
  //auto firevec = getVector(tank);
  for( auto friendly : State::Instance().getPlayerTanks() ) {
    if( friendly.getID() == shooter.getID()) {
      continue;
    }
    double x = friendly.getx();
    double y = friendly.gety();

    double x1, y1, x2, y2 , x3, y3, x4, y4;
    x1 = x - 2; y1 = y - 2; x2 = x + 2; y2 = y + 2; x3 = x - 2; y3 = y + 2; x4 = x + 2; y4 =y - 2;

    double angle1, angle2, angle3, angle4, angle2target;
    angle2target = getAngle(shooter.getx(), shooter.gety(), target.getx(), target.gety());
    angle1 = getAngle(shooter.getx(), shooter.gety(), x1, y1);
    angle2 = getAngle(shooter.getx(), shooter.gety(), x2, y2);
    angle3 = getAngle(shooter.getx(), shooter.gety(), x3, y3);
    angle4 = getAngle(shooter.getx(), shooter.gety(), x4, y4);
    auto result = std::minmax({angle1,angle2,angle3,angle4});
    auto max = result.second;
    auto min = result.first;
    if( angle2target < max && angle2target > min ) {
      return true;
    }
  }
  return false;
}
<commit_msg>Tanks go ham now.<commit_after>#pragma once
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <vector>

#include "command.hpp"
#include "tank.hpp"
#include "state.hpp"

class TankManager {
public:
  void Act();
  Tank getClosestEnemyTank(Tank tank);
  double getDistance(Tank tank1, Tank tank2);

  void aimAt(Tank shooter, Tank target);
  double getShellTravelTime(Tank tank, Tank tank2);

  double getAngle(double x , double y, double x1, double y1);
  bool isFriendinLine(Tank shooter, Tank target);

  std::pair<double,double> getVector(Tank tank);
  std::pair<double, double> getVector(double x, double y, double x1, double y2);
};

void TankManager::Act() {
  State &state = State::Instance();

  // If we don't have any tanks yet don't act
  if(state.getPlayerTanks().empty() || state.getEnemyTanks().empty()) {
    std::cout << "we're all out of tanks" << std::endl;
    std::cout << "player tanks: " << state.getPlayerTanks().size() << std::endl;
    std::cout << "enemy tanks: " << state.getEnemyTanks().size() << std::endl;
    return;
  }

  for (auto tank : state.getPlayerTanks()) {
    if(!tank.isAlive()) {
      continue;
    }
    Tank target = getClosestEnemyTank(tank);

    // Aim!
    aimAt(tank, target);

    // Fire!
    if (isFriendinLine(tank,target)) {
      tank.StopFire();
    }
    else {
      tank.Fire();
    }

    // Move!
    srand(time(0));
    if(rand() % 2) {
      tank.Move(FWD, 10);
    } else {
      tank.Move(REV, 10);
    }
  }
}

Tank TankManager::getClosestEnemyTank(Tank shooter) {
  State &state = State::Instance();
  Tank target = state.getEnemyTanks()[0];
  for (const auto &tank : state.getEnemyTanks()) {
    if (getDistance(shooter, target) > getDistance(shooter, tank)) {
      target = tank;
    }
  }
  return target;
}

void TankManager::aimAt(Tank shooter, Tank target) {
  double angle = atan2(target.gety() - shooter.gety(), target.getx() - shooter.getx());
  if(angle < 0) {
    angle = angle + (2 * M_PI);
  }
  double current = shooter.getturret();
  double amount = angle - current;
  if(amount > 0) {
    shooter.RotateTurret(CCW, amount / 2);
    shooter.Rotate(CCW, amount / 2);
  } else {
    shooter.RotateTurret(CW, -amount / 2);
    shooter.Rotate(CW, -amount / 2);
  }
}

double TankManager::getDistance(Tank tank1, Tank tank2) {
  return std::pow(tank1.getx() - tank2.getx(), 2) + std::pow(tank1.gety() - tank2.gety(), 2);
}

double TankManager::getShellTravelTime(Tank tank, Tank tank2) {
  double dist = getDistance(tank, tank2);
  return dist / 30;
}

std::pair<double,double> TankManager::getVector(Tank tank) {
  std::pair<double,double> vec;
  vec.first = cos(tank.getturret());
  vec.second = sin(tank.getturret());
  return vec;
}

std::pair<double, double> TankManager::getVector(double x, double y, double x1, double y1) {
  std::pair<double, double> vec;
  vec.first = x - x1;
  vec.second = y - y1;
  return vec;
}

double TankManager::getAngle(double x , double y, double x1, double y1) {
  double angle = atan2(x- y, x1 - y1);
  if(angle < 0) {
    angle = angle + (2 * M_PI);
  }
  return angle;
}

bool TankManager::isFriendinLine(Tank shooter, Tank target) {
  //auto firevec = getVector(tank);
  for( auto friendly : State::Instance().getPlayerTanks() ) {
    if( friendly.getID() == shooter.getID()) {
      continue;
    }
    double x = friendly.getx();
    double y = friendly.gety();

    double x1, y1, x2, y2 , x3, y3, x4, y4;
    x1 = x - 2; y1 = y - 2; x2 = x + 2; y2 = y + 2; x3 = x - 2; y3 = y + 2; x4 = x + 2; y4 =y - 2;

    double angle1, angle2, angle3, angle4, angle2target;
    angle2target = getAngle(shooter.getx(), shooter.gety(), target.getx(), target.gety());
    angle1 = getAngle(shooter.getx(), shooter.gety(), x1, y1);
    angle2 = getAngle(shooter.getx(), shooter.gety(), x2, y2);
    angle3 = getAngle(shooter.getx(), shooter.gety(), x3, y3);
    angle4 = getAngle(shooter.getx(), shooter.gety(), x4, y4);
    auto result = std::minmax({angle1,angle2,angle3,angle4});
    auto max = result.second;
    auto min = result.first;
    if( angle2target < max && angle2target > min ) {
      return true;
    }
  }
  return false;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Sacha Refshauge
 *
 */
// Blackberry implementation of the framework.

#include <pwd.h>
#include <unistd.h>
#include <string>

#include "BlackberryMain.h"

// Simple implementations of System functions

void SystemToast(const char *text) {
	dialog_instance_t dialog = 0;
	dialog_create_toast(&dialog);
	dialog_set_toast_message_text(dialog, text);
	dialog_set_toast_position(dialog, DIALOG_POSITION_TOP_CENTER);
	dialog_show(dialog);
}

void ShowAd(int x, int y, bool center_x) {
}

void ShowKeyboard() {
	virtualkeyboard_show();
}

void Vibrate(int length_ms) {
	vibration_request(VIBRATION_INTENSITY_LOW, 200 /* intensity (1-100), duration (ms) */);
}

void LaunchBrowser(const char *url)
{
	char* error;
	navigator_invoke(url, &error);
}

void LaunchMarket(const char *url)
{
	char* error;
	navigator_invoke(url, &error);
}

void LaunchEmail(const char *email_address)
{
	char* error;
	navigator_invoke((std::string("mailto:") + email_address).c_str(), &error);
}

InputState input_state;

// Input
const unsigned int buttonMappings[18] = {
	KEYCODE_K,          //Cross
	KEYCODE_L,          //Circle
	KEYCODE_J,          //Square
	KEYCODE_I,          //Triangle
	KEYCODE_Q,          //LBUMPER
	KEYCODE_P,          //RBUMPER
	KEYCODE_SPACE,      //START
	KEYCODE_ZERO,       //SELECT
	KEYCODE_W,          //UP
	KEYCODE_S,          //DOWN
	KEYCODE_A,          //LEFT
	KEYCODE_D,          //RIGHT
	0,                  //MENU (SwipeDown)
	KEYCODE_BACKSPACE,  //BACK
	KEYCODE_W,          //JOY UP
	KEYCODE_S,          //JOY DOWN
	KEYCODE_A,          //JOY LEFT
	KEYCODE_D,          //JOY RIGHT
};

void SimulateGamepad(InputState *input) {
	input->pad_lstick_x = 0;
	input->pad_lstick_y = 0;
	input->pad_rstick_x = 0;
	input->pad_rstick_y = 0;

	if (input->pad_buttons & PAD_BUTTON_JOY_UP)
		input->pad_lstick_y=1;
	else if (input->pad_buttons & PAD_BUTTON_JOY_DOWN)
		input->pad_lstick_y=-1;
	if (input->pad_buttons & PAD_BUTTON_JOY_LEFT)
		input->pad_lstick_x=-1;
	else if (input->pad_buttons & PAD_BUTTON_JOY_RIGHT)
		input->pad_lstick_x=1;
}

void BlackberryMain::handleInput(screen_event_t screen_event)
{
	int val, buttons, pointerId;
	int pair[2];
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &val);
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION, pair);
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pointerId);

	input_state.mouse_valid = true;
	switch(val)
	{
	// Touchscreen
	case SCREEN_EVENT_MTOUCH_TOUCH:
	case SCREEN_EVENT_MTOUCH_RELEASE: 	// Up, down
		input_state.pointer_down[pointerId] = (val == SCREEN_EVENT_MTOUCH_TOUCH);
	case SCREEN_EVENT_MTOUCH_MOVE:
		input_state.pointer_x[pointerId] = pair[0] * dpi_scale;
		input_state.pointer_y[pointerId] = pair[1] * dpi_scale;
		break;
	// Mouse, Simulator
    case SCREEN_EVENT_POINTER:
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS,
			&buttons);
		if (buttons == SCREEN_LEFT_MOUSE_BUTTON) { 			// Down
			input_state.pointer_x[pointerId] = pair[0] * dpi_scale;
			input_state.pointer_y[pointerId] = pair[1] * dpi_scale;
			input_state.pointer_down[pointerId] = true;
		} else if (input_state.pointer_down[pointerId]) {	// Up
			input_state.pointer_x[pointerId] = pair[0] * dpi_scale;
			input_state.pointer_y[pointerId] = pair[1] * dpi_scale;
			input_state.pointer_down[pointerId] = false;
		}
		break;
	// Keyboard
	case SCREEN_EVENT_KEYBOARD:
		int flags, value;
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &value);
		for (int b = 0; b < 14; b++) {
			if (value == buttonMappings[b] & 0xFF) {
				if (flags & KEY_DOWN)
					pad_buttons |= (1<<b);
				else
					pad_buttons &= ~(1<<b);
			}
		}
		break;
	// Gamepad
	case SCREEN_EVENT_GAMEPAD:
	case SCREEN_EVENT_JOYSTICK:
		char device_id[16];
#define DIR_KEYS SCREEN_DPAD_UP_GAME_BUTTON | SCREEN_DPAD_DOWN_GAME_BUTTON | SCREEN_DPAD_LEFT_GAME_BUTTON | SCREEN_DPAD_RIGHT_GAME_BUTTON
		screen_device_t device;
		screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_DEVICE, (void**)&device);
		screen_get_device_property_cv(device, SCREEN_PROPERTY_ID_STRING, sizeof(device_id), device_id);
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &buttons);
		// Map the buttons integer to our mappings
		if (strstr(device_id, "057E-0306")) // Wiimote
			controller_buttons = (buttons & (SCREEN_A_GAME_BUTTON | SCREEN_B_GAME_BUTTON)) << 2 |
			                     (buttons & (SCREEN_X_GAME_BUTTON | SCREEN_Y_GAME_BUTTON)) >> 3;
		else
			controller_buttons = (buttons & (SCREEN_A_GAME_BUTTON | SCREEN_B_GAME_BUTTON)) |
			                     (buttons & (SCREEN_X_GAME_BUTTON | SCREEN_Y_GAME_BUTTON)) >> 1;
		controller_buttons |= (buttons & (SCREEN_MENU1_GAME_BUTTON | SCREEN_MENU2_GAME_BUTTON)) |
		                      (buttons & SCREEN_L1_GAME_BUTTON) >> 6 | (buttons & SCREEN_R1_GAME_BUTTON) >> 8 |
		                      (buttons & DIR_KEYS) >> 8 |
		                      (buttons & DIR_KEYS) >> 2;
		break;
	case SCREEN_EVENT_DISPLAY:
		screen_display_t new_dpy = NULL;
		screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_DISPLAY, (void **)&new_dpy);
		static int hits = 0;
		hits++;
		for (int i = 0; i < ndisplays; i++) {
			if (new_dpy != screen_dpy[i])
				continue;
			int active = 0;
			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_ATTACHED, &active);
			if (active) {
				int size[2];
				screen_get_display_property_iv(screen_dpy[i], SCREEN_PROPERTY_SIZE, size);
				if (size[0] == 0 || size[1] == 0)
					active = 0;
			}
			if (active && !displays[i].attached)
				realiseDisplay(i);
			else if (!active && displays[i].attached && displays[i].realised)
				unrealiseDisplay(i);
			displays[i].attached = active;
		}
		break;
	}
}

void BlackberryMain::startMain(int argc, char *argv[]) {
	// Receive events from window manager
	screen_create_context(&screen_cxt, 0);
	// Initialise Blackberry Platform Services
	bps_initialize();
	// TODO: Enable/disable based on setting
	sensor_set_rate(SENSOR_TYPE_ACCELEROMETER, 25000);
	sensor_request_events(SENSOR_TYPE_ACCELEROMETER);

	net::Init();
	startDisplays();
	//eglMakeCurrent(egl_disp[0], egl_surf[0], egl_surf[0], egl_ctx[0]);
	NativeInit(argc, (const char **)argv, "/accounts/1000/shared/misc/", "data/", "BADCOFFEE");
	NativeInitGraphics();
	screen_request_events(screen_cxt);
	navigator_request_events(0);
	dialog_request_events(0);
	vibration_request_events(0);
	audio = new BlackberryAudio();
	runMain();
}

void BlackberryMain::runMain() {
	bool running = true;
	while (running) {
		input_state.mouse_valid = false;
		input_state.accelerometer_valid = false;
		SimulateGamepad(&input_state);
		while (true) {
			// Handle Blackberry events
			bps_event_t *event = NULL;
			bps_get_event(&event, 0);
			if (event == NULL)
				break; // Ran out of events
			int domain = bps_event_get_domain(event);
			if (domain == screen_get_domain()) {
				handleInput(screen_event_get_event(event));
			} else if (domain == navigator_get_domain()) {
				switch(bps_event_get_code(event))
				{
				case NAVIGATOR_BACK:
				case NAVIGATOR_SWIPE_DOWN:
					pad_buttons |= PAD_BUTTON_MENU;
					break;
				case NAVIGATOR_EXIT:
					NativeShutdown();
					exit(0);
					break;
				}
			} else if (domain == sensor_get_domain()) {
				if (SENSOR_ACCELEROMETER_READING == bps_event_get_code(event)) {
					float x, y, z;
					sensor_event_get_xyz(event, &x, &y, &z);
					if (pixel_xres == 1024 || pixel_xres == 720) // Q10 has this negative and reversed
					{
						input_state.acc.x = -y;
						input_state.acc.y = -x;
					} else {
						input_state.acc.x = x;
						input_state.acc.y = y;
					}
					input_state.acc.z = z;
				}
			}
		}
		input_state.pad_buttons = pad_buttons | controller_buttons;
		pad_buttons &= ~PAD_BUTTON_MENU;
		UpdateInputState(&input_state);
		NativeUpdate(input_state);
		EndInputState(&input_state);
		// Work in Progress
		// Currently: Render to HDMI port (eg. 1080p) when in game. Render to device when in menu.
		// Right now, hotswapping displays is not working. Temporarily disable.
		// Idea: Render to all displays. Controls go to internal, game goes to external(s).
#if 0
		if (globalUIState == UISTATE_INGAME && !emulating)
		{
			emulating = true;
			switchDisplay(screen_emu);
		} else if (globalUIState != UISTATE_INGAME && emulating) {
			emulating = false;
			switchDisplay(screen_ui);
		}
#endif
		NativeRender();
		time_update();
		// This handles VSync
		if (false && emulating) // Temporarily disable
			eglSwapBuffers(egl_disp[screen_emu], egl_surf[screen_emu]);
		else
			eglSwapBuffers(egl_disp[screen_ui], egl_surf[screen_ui]);
	}
	endMain();
}

void BlackberryMain::endMain() {
	screen_stop_events(screen_cxt);
	bps_shutdown();
	NativeShutdownGraphics();
	delete audio;
	NativeShutdown();
	killDisplays();
	net::Shutdown();
	screen_destroy_context(screen_cxt);
}

// Entry Point
int main(int argc, char *argv[]) {
	BlackberryMain emu;
	emu.startMain(argc, argv);
	exit(0);
	return 0;
}
<commit_msg>Initialise buttons so we don't get stuck keys.<commit_after>/*
 * Copyright (c) 2013 Sacha Refshauge
 *
 */
// Blackberry implementation of the framework.

#include <pwd.h>
#include <unistd.h>
#include <string>

#include "BlackberryMain.h"

// Simple implementations of System functions

void SystemToast(const char *text) {
	dialog_instance_t dialog = 0;
	dialog_create_toast(&dialog);
	dialog_set_toast_message_text(dialog, text);
	dialog_set_toast_position(dialog, DIALOG_POSITION_TOP_CENTER);
	dialog_show(dialog);
}

void ShowAd(int x, int y, bool center_x) {
}

void ShowKeyboard() {
	virtualkeyboard_show();
}

void Vibrate(int length_ms) {
	vibration_request(VIBRATION_INTENSITY_LOW, 200 /* intensity (1-100), duration (ms) */);
}

void LaunchBrowser(const char *url)
{
	char* error;
	navigator_invoke(url, &error);
}

void LaunchMarket(const char *url)
{
	char* error;
	navigator_invoke(url, &error);
}

void LaunchEmail(const char *email_address)
{
	char* error;
	navigator_invoke((std::string("mailto:") + email_address).c_str(), &error);
}

InputState input_state;

// Input
const unsigned int buttonMappings[18] = {
	KEYCODE_K,          //Cross
	KEYCODE_L,          //Circle
	KEYCODE_J,          //Square
	KEYCODE_I,          //Triangle
	KEYCODE_Q,          //LBUMPER
	KEYCODE_P,          //RBUMPER
	KEYCODE_SPACE,      //START
	KEYCODE_ZERO,       //SELECT
	KEYCODE_W,          //UP
	KEYCODE_S,          //DOWN
	KEYCODE_A,          //LEFT
	KEYCODE_D,          //RIGHT
	0,                  //MENU (SwipeDown)
	KEYCODE_BACKSPACE,  //BACK
	KEYCODE_W,          //JOY UP
	KEYCODE_S,          //JOY DOWN
	KEYCODE_A,          //JOY LEFT
	KEYCODE_D,          //JOY RIGHT
};

void SimulateGamepad(InputState *input) {
	input->pad_lstick_x = 0;
	input->pad_lstick_y = 0;
	input->pad_rstick_x = 0;
	input->pad_rstick_y = 0;

	if (input->pad_buttons & PAD_BUTTON_JOY_UP)
		input->pad_lstick_y=1;
	else if (input->pad_buttons & PAD_BUTTON_JOY_DOWN)
		input->pad_lstick_y=-1;
	if (input->pad_buttons & PAD_BUTTON_JOY_LEFT)
		input->pad_lstick_x=-1;
	else if (input->pad_buttons & PAD_BUTTON_JOY_RIGHT)
		input->pad_lstick_x=1;
}

void BlackberryMain::handleInput(screen_event_t screen_event)
{
	int val, buttons, pointerId;
	int pair[2];
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &val);
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_SOURCE_POSITION, pair);
	screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TOUCH_ID, &pointerId);

	input_state.mouse_valid = true;
	switch(val)
	{
	// Touchscreen
	case SCREEN_EVENT_MTOUCH_TOUCH:
	case SCREEN_EVENT_MTOUCH_RELEASE: 	// Up, down
		input_state.pointer_down[pointerId] = (val == SCREEN_EVENT_MTOUCH_TOUCH);
	case SCREEN_EVENT_MTOUCH_MOVE:
		input_state.pointer_x[pointerId] = pair[0] * dpi_scale;
		input_state.pointer_y[pointerId] = pair[1] * dpi_scale;
		break;
	// Mouse, Simulator
    case SCREEN_EVENT_POINTER:
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS,
			&buttons);
		if (buttons == SCREEN_LEFT_MOUSE_BUTTON) { 			// Down
			input_state.pointer_x[pointerId] = pair[0] * dpi_scale;
			input_state.pointer_y[pointerId] = pair[1] * dpi_scale;
			input_state.pointer_down[pointerId] = true;
		} else if (input_state.pointer_down[pointerId]) {	// Up
			input_state.pointer_x[pointerId] = pair[0] * dpi_scale;
			input_state.pointer_y[pointerId] = pair[1] * dpi_scale;
			input_state.pointer_down[pointerId] = false;
		}
		break;
	// Keyboard
	case SCREEN_EVENT_KEYBOARD:
		int flags, value;
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM, &value);
		for (int b = 0; b < 14; b++) {
			if (value == buttonMappings[b] & 0xFF) {
				if (flags & KEY_DOWN)
					pad_buttons |= (1<<b);
				else
					pad_buttons &= ~(1<<b);
			}
		}
		break;
	// Gamepad
	case SCREEN_EVENT_GAMEPAD:
	case SCREEN_EVENT_JOYSTICK:
		char device_id[16];
#define DIR_KEYS SCREEN_DPAD_UP_GAME_BUTTON | SCREEN_DPAD_DOWN_GAME_BUTTON | SCREEN_DPAD_LEFT_GAME_BUTTON | SCREEN_DPAD_RIGHT_GAME_BUTTON
		screen_device_t device;
		screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_DEVICE, (void**)&device);
		screen_get_device_property_cv(device, SCREEN_PROPERTY_ID_STRING, sizeof(device_id), device_id);
		screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_BUTTONS, &buttons);
		// Map the buttons integer to our mappings
		if (strstr(device_id, "057E-0306")) // Wiimote
			controller_buttons = (buttons & (SCREEN_A_GAME_BUTTON | SCREEN_B_GAME_BUTTON)) << 2 |
			                     (buttons & (SCREEN_X_GAME_BUTTON | SCREEN_Y_GAME_BUTTON)) >> 3;
		else
			controller_buttons = (buttons & (SCREEN_A_GAME_BUTTON | SCREEN_B_GAME_BUTTON)) |
			                     (buttons & (SCREEN_X_GAME_BUTTON | SCREEN_Y_GAME_BUTTON)) >> 1;
		controller_buttons |= (buttons & (SCREEN_MENU1_GAME_BUTTON | SCREEN_MENU2_GAME_BUTTON)) |
		                      (buttons & SCREEN_L1_GAME_BUTTON) >> 6 | (buttons & SCREEN_R1_GAME_BUTTON) >> 8 |
		                      (buttons & DIR_KEYS) >> 8 |
		                      (buttons & DIR_KEYS) >> 2;
		break;
	case SCREEN_EVENT_DISPLAY:
		screen_display_t new_dpy = NULL;
		screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_DISPLAY, (void **)&new_dpy);
		static int hits = 0;
		hits++;
		for (int i = 0; i < ndisplays; i++) {
			if (new_dpy != screen_dpy[i])
				continue;
			int active = 0;
			screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_ATTACHED, &active);
			if (active) {
				int size[2];
				screen_get_display_property_iv(screen_dpy[i], SCREEN_PROPERTY_SIZE, size);
				if (size[0] == 0 || size[1] == 0)
					active = 0;
			}
			if (active && !displays[i].attached)
				realiseDisplay(i);
			else if (!active && displays[i].attached && displays[i].realised)
				unrealiseDisplay(i);
			displays[i].attached = active;
		}
		break;
	}
}

void BlackberryMain::startMain(int argc, char *argv[]) {
	// Receive events from window manager
	screen_create_context(&screen_cxt, 0);
	// Initialise Blackberry Platform Services
	bps_initialize();
	// TODO: Enable/disable based on setting
	sensor_set_rate(SENSOR_TYPE_ACCELEROMETER, 25000);
	sensor_request_events(SENSOR_TYPE_ACCELEROMETER);
	pad_buttons = 0;
	controller_buttons = 0;

	net::Init();
	startDisplays();
	//eglMakeCurrent(egl_disp[0], egl_surf[0], egl_surf[0], egl_ctx[0]);
	NativeInit(argc, (const char **)argv, "/accounts/1000/shared/misc/", "data/", "BADCOFFEE");
	NativeInitGraphics();
	screen_request_events(screen_cxt);
	navigator_request_events(0);
	dialog_request_events(0);
	vibration_request_events(0);
	audio = new BlackberryAudio();
	runMain();
}

void BlackberryMain::runMain() {
	bool running = true;
	while (running) {
		input_state.mouse_valid = false;
		input_state.accelerometer_valid = false;
		SimulateGamepad(&input_state);
		while (true) {
			// Handle Blackberry events
			bps_event_t *event = NULL;
			bps_get_event(&event, 0);
			if (event == NULL)
				break; // Ran out of events
			int domain = bps_event_get_domain(event);
			if (domain == screen_get_domain()) {
				handleInput(screen_event_get_event(event));
			} else if (domain == navigator_get_domain()) {
				switch(bps_event_get_code(event))
				{
				case NAVIGATOR_BACK:
				case NAVIGATOR_SWIPE_DOWN:
					pad_buttons |= PAD_BUTTON_MENU;
					break;
				case NAVIGATOR_EXIT:
					NativeShutdown();
					exit(0);
					break;
				}
			} else if (domain == sensor_get_domain()) {
				if (SENSOR_ACCELEROMETER_READING == bps_event_get_code(event)) {
					float x, y, z;
					sensor_event_get_xyz(event, &x, &y, &z);
					if (pixel_xres == 1024 || pixel_xres == 720) // Q10 has this negative and reversed
					{
						input_state.acc.x = -y;
						input_state.acc.y = -x;
					} else {
						input_state.acc.x = x;
						input_state.acc.y = y;
					}
					input_state.acc.z = z;
				}
			}
		}
		input_state.pad_buttons = pad_buttons | controller_buttons;
		pad_buttons &= ~PAD_BUTTON_MENU;
		UpdateInputState(&input_state);
		NativeUpdate(input_state);
		EndInputState(&input_state);
		// Work in Progress
		// Currently: Render to HDMI port (eg. 1080p) when in game. Render to device when in menu.
		// Right now, hotswapping displays is not working. Temporarily disable.
		// Idea: Render to all displays. Controls go to internal, game goes to external(s).
#if 0
		if (globalUIState == UISTATE_INGAME && !emulating)
		{
			emulating = true;
			switchDisplay(screen_emu);
		} else if (globalUIState != UISTATE_INGAME && emulating) {
			emulating = false;
			switchDisplay(screen_ui);
		}
#endif
		NativeRender();
		time_update();
		// This handles VSync
		if (false && emulating) // Temporarily disable
			eglSwapBuffers(egl_disp[screen_emu], egl_surf[screen_emu]);
		else
			eglSwapBuffers(egl_disp[screen_ui], egl_surf[screen_ui]);
	}
	endMain();
}

void BlackberryMain::endMain() {
	screen_stop_events(screen_cxt);
	bps_shutdown();
	NativeShutdownGraphics();
	delete audio;
	NativeShutdown();
	killDisplays();
	net::Shutdown();
	screen_destroy_context(screen_cxt);
}

// Entry Point
int main(int argc, char *argv[]) {
	BlackberryMain emu;
	emu.startMain(argc, argv);
	exit(0);
	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
using std::begin; using std::end; using std::cout; using std::endl; using std::vector; using std::size_t;

bool compare(const int lhs[], size_t lsize, const int rhs[], size_t rsize)
{
    if (lsize != rsize) return false;
    for (int i = 0; i != lsize; ++i)
        if (lhs[i] != rhs[i]) return false;
    return true;
}

bool compare(vector<int> const& lhs, vector<int>& rhs)
{
    return lhs == rhs;
}

int main()
{
    int arr1[3] = { 0, 1, 2 };
    int arr2[3] = { 0, 2, 4 };
    auto result = compare(arr1, sizeof(arr1) / sizeof(arr2[0]), arr2, sizeof(arr2[0]));
    cout << "The two arrays are " << (result ? "equal\n" : "unequal\n");

    vector<int> vec1 = { 0, 1, 2 };
    vector<int> vec2 = { 0, 1, 2 };
    result = compare(vec1, vec2);
    cout << "The two vectors are " << (result ? "equal\n" : "unequal\n");

    return 0;
}
<commit_msg>Update ex3_36.cpp<commit_after>#include <iostream>
#include <vector>
using std::begin; using std::end; using std::cout; using std::endl; using std::vector; using std::size_t;

size_t array_size(const int arr[])
{
    return sizeof(arr) / sizeof(arr[0]);
}

bool compare(const int lhs[], const int rhs[])
{
    auto lsize = array_size(lhs);
    auto rsize = array_size(rhs);
    if (lsize != rsize) return false;
    for (int i = 0; i != lsize; ++i)
        if (lhs[i] != rhs[i]) return false;
    return true;
}

bool compare(vector<int> const& lhs, vector<int>& rhs)
{
    return lhs == rhs;
}

int main()
{
    int arr1[3] = { 0, 1, 2 };
    int arr2[3] = { 0, 1, 2 };
    cout << "The two arrays are " << (compare(arr1, arr2) ? "equal\n" : "unequal\n");

    vector<int> vec1 = { 0, 1, 2 };
    vector<int> vec2 = { 0, 1, 3 };
    cout << "The two vectors are " << (compare(vec1, vec2) ? "equal\n" : "unequal\n");

    return 0;
}
<|endoftext|>


<commit_before>//
//  ex9_34.cpp
//  Exercise 9.34
//
//  Created by pezy on 12/3/14.
//  Copyright (c) 2014 pezy. All rights reserved.
//
//  @Brief  Assuming vi is a container of ints that includes even and odd
//          values, predict the behavior of the following loop. After you've
//          analyzed this loop, write a program to test whether your expectations
//          were correct.
//
//			iter = vi.begin();
//			while (iter != vi.end())
//				if (*iter % 2)
//					iter = vi.insert(iter, *iter);
//				++iter;
//
//  @Answer "infinite loop". Casue the `++iter` out of the `while` loop. But
//          even through add brackets it is still infinite loop.
//          Fixed following.

#include <iostream>
using std::cout;
using std::endl;

#include <vector>
using std::vector;

int main()
{
    vector<int> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    auto iter = vi.begin();
    while (iter != vi.end())
    {
        if (*iter % 2)
        {
            iter = vi.insert(iter, *iter);
            ++iter;
        }
        ++iter;
    }

    for (auto i : vi)
        cout << i << " ";
    cout << endl;
}

<commit_msg>Update ex9_34.cpp<commit_after>//
//  ex9_34.cpp
//  Exercise 9.34
//
//  Created by pezy on 12/3/14.
//  Copyright (c) 2014 pezy. All rights reserved.
//
//  @Brief  Assuming vi is a container of ints that includes even and odd
//          values, predict the behavior of the following loop. After you've
//          analyzed this loop, write a program to test whether your expectations
//          were correct.
//
//			iter = vi.begin();
//			while (iter != vi.end())
//				if (*iter % 2)
//					iter = vi.insert(iter, *iter);
//				++iter;
//
//  @Answer "infinite loop". Casue the `++iter` out of the `while` loop. But
//          even through add brackets it is still infinite loop.
//          Fixed following:

#include <iostream>
using std::cout;
using std::endl;

#include <vector>
using std::vector;

int main()
{
    vector<int> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    auto iter = vi.begin();
    while (iter != vi.end())
    {
        if (*iter % 2)
        {
            iter = vi.insert(iter, *iter);
            ++iter;
        }
        ++iter;
    }

    for (auto i : vi)
        cout << i << " ";
    cout << endl;
}

<|endoftext|>


<commit_before>//! @file   Exercise 9.49
//! @author pezy
//! @date   2014-12-05
//! @Brief  A letter has an ascender if, as with d or f, part of the letter
//! extends above the middle of the line.
//          A letter has a descender if, as with p or g, part of the letter
//          extends below the line.
//          Write a program that reads a file containing words and reports the
//          longest word that contains
//          neither ascenders nor descenders.

#include <string>
#include <fstream>
#include <iostream>

using std::string;
using std::ifstream;
using std::cout;
using std::endl;

int main()
{
    ifstream ifs("../data/letter.txt");
    if (!ifs) return -1;
    string longest_word;
    for (string word; ifs >> word;)
        if (word.find_first_not_of("aceimnorsuvwxz") == string::npos &&
            word.size() > longest_word.size())
            longest_word = word;

    cout << longest_word << endl;
}
<commit_msg>Update ex9_49.cpp<commit_after>//! @file   Exercise 9.49
//! @author pezy
//! @date   2014-12-05
//! @Brief  A letter has an ascender if, as with d or f, part of the letter
//          extends above the middle of the line.
//          A letter has a descender if, as with p or g, part of the letter
//          extends below the line.
//          Write a program that reads a file containing words and reports the
//          longest word that contains neither ascenders nor descenders.

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main()
{
    ifstream input("E:\\zzz.txt");
    if(input)
    {
        string longest_word;
        for(string word; input>>word; )
            if((word.find_first_not_of("aceimnorsuvwxz"))==string::npos&&word.size()>longest_word.size())
                longest_word=word;
        cout<<longest_word<<endl;
    }
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	I2C EEPROM ドライバー
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RL78/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/iica_io.hpp"
#include "common/delay.hpp"

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  EEPROM テンプレートクラス
		@param[in]	I2C_IO	i2c I/O クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class I2C_IO>
	class EEPROM {

		static const uint8_t	EEPROM_ADR_ = 0x50;

		I2C_IO&	i2c_;

		uint8_t	ds_;
		bool	exp_;
		bool	ad_mix_;
		uint8_t	pagen_;

		uint8_t i2c_adr_(uint32_t adr) const {
			uint8_t a = EEPROM_ADR_ | ds_;
			if(ad_mix_) {
				if(adr >> 16) a |= 4;
			}
			return a;
		}

	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief 256 バイトまでの EEPROM の ID (0 to 7) @n
				   アドレス指定が１バイトのデバイス
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class M256B : uint8_t {
			ID0,	///< A0=L(0), A1=L(0), A2=L(0)
			ID1,	///< A0=H(1), A1=L(0), A2=L(0)
			ID2,	///< A0=L(0), A1=H(1), A2=L(0)
			ID3,	///< A0=H(1), A1=H(1), A2=L(0)
			ID4,	///< A0=L(0), A1=L(0), A2=H(1)
			ID5,	///< A0=H(1), A1=L(0), A2=H(1)
			ID6,	///< A0=L(0), A1=H(1), A2=H(1)
			ID7,	///< A0=H(1), A1=H(1), A2=H(1)
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief 64K バイトまでの EEPROM の ID (0 to 7) @n
				   アドレス指定が２バイトのデバイス
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class M64KB : uint8_t {
			ID0,	///< A0=L(0), A1=L(0), A2=L(0)
			ID1,	///< A0=H(1), A1=L(0), A2=L(0)
			ID2,	///< A0=L(0), A1=H(1), A2=L(0)
			ID3,	///< A0=H(1), A1=H(1), A2=L(0)
			ID4,	///< A0=L(0), A1=L(0), A2=H(1)
			ID5,	///< A0=H(1), A1=L(0), A2=H(1)
			ID6,	///< A0=L(0), A1=H(1), A2=H(1)
			ID7,	///< A0=H(1), A1=H(1), A2=H(1)
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief 128K バイトの EEPROM の ID (0 to 3) @n
				   アドレス指定が２バイトのデバイス @n
				   A2 端子が、バンクセレクトに使われるデバイス
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class M128KB : uint8_t {
			ID0,	///< A0=L(0), A1=L(0)
			ID1,	///< A0=H(1), A1=L(0)
			ID2,	///< A0=L(0), A1=H(1)
			ID3,	///< A0=H(1), A1=H(1)
		};

		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	i2c	i2c_io クラスを参照で渡す
		 */
		//-----------------------------------------------------------------//
		EEPROM(I2C_IO& i2c) : i2c_(i2c), ds_(0),
			exp_(false), ad_mix_(false), pagen_(1) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	アドレス指定１バイトの EEPROM を開始
			@param[in]	type	デバイスのタイプとID
			@param[in]	pagen	ページサイズ（書き込み一時バッファのサイズ）
		 */
		//-----------------------------------------------------------------//
		void start(M256B type_id, uint8_t pagen) {
			ds_ = static_cast<uint8_t>(type_id);
			exp_ = false;
			ad_mix_ = false;
			pagen_ = pagen;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	アドレス指定２バイトの EEPROM を開始
			@param[in]	type	デバイスのタイプとID
			@param[in]	pagen	ページサイズ（書き込み一時バッファのサイズ）
		 */
		//-----------------------------------------------------------------//
		void start(M64KB type_id, uint8_t pagen) {
			ds_ = static_cast<uint8_t>(type_id);
			exp_ = true;
			ad_mix_ = false;
			pagen_ = pagen;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	アドレス指定２バイトで、「A2」がバンクの EEPROM を開始
			@param[in]	type	デバイスのタイプとID
			@param[in]	pagen	ページサイズ（書き込み一時バッファのサイズ）
		 */
		//-----------------------------------------------------------------//
		void start(M128KB type_id, uint8_t pagen) {
			ds_ = static_cast<uint8_t>(type_id);
			exp_ = true;
			ad_mix_ = true;
			pagen_ = pagen;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	書き込み状態の検査
			@param[in]	adr	検査アドレス
			@return 「false」なら、書き込み中
		 */
		//-----------------------------------------------------------------//
		bool get_write_state(uint32_t adr) const {
			uint8_t tmp[1];
			return read(adr, tmp, 1);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	書き込み同期
			@param[in]	adr	検査アドレス
			@param[in]	delay 待ち時間（10us単位）
			@return デバイスエラーなら「false」
		 */
		//-----------------------------------------------------------------//
		bool sync_write(uint32_t adr, uint16_t delay = 600) const {
			bool ok = false;
			for(uint16_t i = 0; i < delay; ++i) {
				utils::delay::micro_second(10);
				uint8_t tmp[1];
				if(read(adr, tmp, 1)) {
					ok = true;
					break;
				}
			}
			return ok;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	EEPROM 読み出し
			@param[in]	adr	読み出しアドレス
			@param[out]	dst	先
			@param[in]	len	長さ
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool read(uint32_t adr, uint8_t* dst, uint16_t len) const {
			uint8_t tmp[2];
			if(exp_) {
				tmp[0] = (adr >> 8) & 255;
				tmp[1] =  adr & 255;
				if(!i2c_.send(i2c_adr_(adr), tmp, 2)) {
					return false;
				}
			} else {
				tmp[0] = adr & 255;
				if(!i2c_.send(i2c_adr_(adr), tmp, 1)) {
					return false;
				}
			}
			if(!i2c_.recv(i2c_adr_(adr), dst, len)) {
				return false;
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	EEPROM 書き込み
			@param[in]	adr	書き込みアドレス
			@param[out]	src	元
			@param[in]	len	長さ
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool write(uint32_t adr, const uint8_t* src, uint16_t len) const {
			while(len > 0) {
				uint16_t l = pagen_ - (adr & (pagen_ - 1));
				if(len < l) l = len;
				if(exp_) {
					if(!i2c_.send(i2c_adr_(adr), adr >> 8, adr & 255, src, l)) {
						return false;
					}
				} else {
					if(!i2c_.send(i2c_adr_(adr), adr & 255, src, l)) {
						return false;
					}
				}
				src += l;
				len -= l;
				if(len) {  // 書き込み終了を待つポーリング
					if(!sync_write(adr)) {
						return false;
					}
				}
				adr += l;
			}
			return true;
		}
	};
}
<commit_msg>cleanup include path<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	I2C EEPROM ドライバー
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RL78/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/delay.hpp"

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  EEPROM テンプレートクラス
		@param[in]	I2C_IO	i2c I/O クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class I2C_IO>
	class EEPROM {

		static const uint8_t	EEPROM_ADR_ = 0x50;

		I2C_IO&	i2c_;

		uint8_t	ds_;
		bool	exp_;
		bool	ad_mix_;
		uint8_t	pagen_;

		uint8_t i2c_adr_(uint32_t adr) const {
			uint8_t a = EEPROM_ADR_ | ds_;
			if(ad_mix_) {
				if(adr >> 16) a |= 4;
			}
			return a;
		}

	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief 256 バイトまでの EEPROM の ID (0 to 7) @n
				   アドレス指定が１バイトのデバイス
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class M256B : uint8_t {
			ID0,	///< A0=L(0), A1=L(0), A2=L(0)
			ID1,	///< A0=H(1), A1=L(0), A2=L(0)
			ID2,	///< A0=L(0), A1=H(1), A2=L(0)
			ID3,	///< A0=H(1), A1=H(1), A2=L(0)
			ID4,	///< A0=L(0), A1=L(0), A2=H(1)
			ID5,	///< A0=H(1), A1=L(0), A2=H(1)
			ID6,	///< A0=L(0), A1=H(1), A2=H(1)
			ID7,	///< A0=H(1), A1=H(1), A2=H(1)
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief 64K バイトまでの EEPROM の ID (0 to 7) @n
				   アドレス指定が２バイトのデバイス
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class M64KB : uint8_t {
			ID0,	///< A0=L(0), A1=L(0), A2=L(0)
			ID1,	///< A0=H(1), A1=L(0), A2=L(0)
			ID2,	///< A0=L(0), A1=H(1), A2=L(0)
			ID3,	///< A0=H(1), A1=H(1), A2=L(0)
			ID4,	///< A0=L(0), A1=L(0), A2=H(1)
			ID5,	///< A0=H(1), A1=L(0), A2=H(1)
			ID6,	///< A0=L(0), A1=H(1), A2=H(1)
			ID7,	///< A0=H(1), A1=H(1), A2=H(1)
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief 128K バイトの EEPROM の ID (0 to 3) @n
				   アドレス指定が２バイトのデバイス @n
				   A2 端子が、バンクセレクトに使われるデバイス
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class M128KB : uint8_t {
			ID0,	///< A0=L(0), A1=L(0)
			ID1,	///< A0=H(1), A1=L(0)
			ID2,	///< A0=L(0), A1=H(1)
			ID3,	///< A0=H(1), A1=H(1)
		};

		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	i2c	i2c_io クラスを参照で渡す
		 */
		//-----------------------------------------------------------------//
		EEPROM(I2C_IO& i2c) : i2c_(i2c), ds_(0),
			exp_(false), ad_mix_(false), pagen_(1) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	アドレス指定１バイトの EEPROM を開始
			@param[in]	type	デバイスのタイプとID
			@param[in]	pagen	ページサイズ（書き込み一時バッファのサイズ）
		 */
		//-----------------------------------------------------------------//
		void start(M256B type_id, uint8_t pagen) {
			ds_ = static_cast<uint8_t>(type_id);
			exp_ = false;
			ad_mix_ = false;
			pagen_ = pagen;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	アドレス指定２バイトの EEPROM を開始
			@param[in]	type	デバイスのタイプとID
			@param[in]	pagen	ページサイズ（書き込み一時バッファのサイズ）
		 */
		//-----------------------------------------------------------------//
		void start(M64KB type_id, uint8_t pagen) {
			ds_ = static_cast<uint8_t>(type_id);
			exp_ = true;
			ad_mix_ = false;
			pagen_ = pagen;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	アドレス指定２バイトで、「A2」がバンクの EEPROM を開始
			@param[in]	type	デバイスのタイプとID
			@param[in]	pagen	ページサイズ（書き込み一時バッファのサイズ）
		 */
		//-----------------------------------------------------------------//
		void start(M128KB type_id, uint8_t pagen) {
			ds_ = static_cast<uint8_t>(type_id);
			exp_ = true;
			ad_mix_ = true;
			pagen_ = pagen;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	書き込み状態の検査
			@param[in]	adr	検査アドレス
			@return 「false」なら、書き込み中
		 */
		//-----------------------------------------------------------------//
		bool get_write_state(uint32_t adr) const {
			uint8_t tmp[1];
			return read(adr, tmp, 1);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	書き込み同期
			@param[in]	adr	検査アドレス
			@param[in]	delay 待ち時間（10us単位）
			@return デバイスエラーなら「false」
		 */
		//-----------------------------------------------------------------//
		bool sync_write(uint32_t adr, uint16_t delay = 600) const {
			bool ok = false;
			for(uint16_t i = 0; i < delay; ++i) {
				utils::delay::micro_second(10);
				uint8_t tmp[1];
				if(read(adr, tmp, 1)) {
					ok = true;
					break;
				}
			}
			return ok;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	EEPROM 読み出し
			@param[in]	adr	読み出しアドレス
			@param[out]	dst	先
			@param[in]	len	長さ
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool read(uint32_t adr, uint8_t* dst, uint16_t len) const {
			uint8_t tmp[2];
			if(exp_) {
				tmp[0] = (adr >> 8) & 255;
				tmp[1] =  adr & 255;
				if(!i2c_.send(i2c_adr_(adr), tmp, 2)) {
					return false;
				}
			} else {
				tmp[0] = adr & 255;
				if(!i2c_.send(i2c_adr_(adr), tmp, 1)) {
					return false;
				}
			}
			if(!i2c_.recv(i2c_adr_(adr), dst, len)) {
				return false;
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	EEPROM 書き込み
			@param[in]	adr	書き込みアドレス
			@param[out]	src	元
			@param[in]	len	長さ
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool write(uint32_t adr, const uint8_t* src, uint16_t len) const {
			while(len > 0) {
				uint16_t l = pagen_ - (adr & (pagen_ - 1));
				if(len < l) l = len;
				if(exp_) {
					if(!i2c_.send(i2c_adr_(adr), adr >> 8, adr & 255, src, l)) {
						return false;
					}
				} else {
					if(!i2c_.send(i2c_adr_(adr), adr & 255, src, l)) {
						return false;
					}
				}
				src += l;
				len -= l;
				if(len) {  // 書き込み終了を待つポーリング
					if(!sync_write(adr)) {
						return false;
					}
				}
				adr += l;
			}
			return true;
		}
	};
}
<|endoftext|>