<commit_before>#include <AltSoftSerial.h>
/**
 *  \brief Software serial port object
 *  \author volodink
 */
AltSoftSerial mySerial;

int c = 0; /**< The variable which is assigned received GPS data
 * for later comparison in getUBX
 */
uint8_t message[60]; /**< The maximum Byte Offset */
/**
 * The first argument to calculate the checksum
 */
uint8_t CK_A = 0, CK_B = 0;
/**< The second argument to calculate the checksum */
/**
 * The first argument to comparison the checksum
 */
uint8_t CK_AU = 0, CK_BU = 0; /**< The second argument to comparison the checksum */
int gpsStep = 0; /**< If the data suits us, this parameter makes the step */
uint8_t UBX_id = 0; /**< Message ID */
uint8_t UBX_class = 0; /**< Message class */
uint8_t meslenL = 0;
uint8_t meslenH = 0;
int16_t meslen = 0;
int count = 0;
boolean gotUBX = false; /**< The parameter which checks getting data */
boolean POSLLH = 0; /**< Geodetic Position Solution; This message outputs
 * the Geodetic position in the currently selected Ellipsoid.
 */
boolean SVINFO = 0;/**< Space Vehicle Information */
boolean SOL = 0;/**< Navigation Solution Information; This message combines Position,
 * velocity and time solution in ECEF, including accuracy figures
 */
boolean VELNED = 0;/**< Velocity Solution in NED */
char GPSdata[40];
long int longitude; /**< Longitude */
float longitudef; /**< Output longitude */
long int latitude; /**< Latitude */
float latitudef; /**< Output latitude */
long int height; /**< Height */
float heightf; /**< Output height */
long int speed3; /**< Longitude */
float speed3f; /**< Speed */
/**
 * GPSfix Type, range 0..5;
 * Is a measure of the communication
 * required for a GPS receiver to acquire
 * satellite signals and navigation data
 */
short int FixType;
short int NumSV; /**< Number of SVs used in Nav Solution */
/**
 * \brief uBlox checksum algorithm
 * \param ubx_data Contains the data over
 * which the checksum is to be calculated.
 */
void ubx_checksum(byte ubx_data) //рассчет контрольной суммы
{
    CK_A += ubx_data;
    CK_B += CK_A;
}
/**
 * \brief Getting and comparing data
 */
void getUBX(void) //Получаем пакет и делаем с ним штуки
{
    if (Serial.available())
    {
        uint8_t c = Serial.read();
        switch (gpsStep)
        {
            case 0:
            {
                if (c == 0xB5){
                    gpsStep++;
                    //         mySerial.print("0");
                }
                break;
            }
            case 1:
            {
                if (c == 0x62){
                    gpsStep++;
                    //          mySerial.print("1");
                }
                else{
                    gpsStep = 0;
                    //        mySerial.println("not62");
                }
                break;
            }
            case 2:
            {
                UBX_class = c;
                ubx_checksum(c);
                gpsStep++;
                //        mySerial.print("2");
                break;
            }
            case 3:
            {
                UBX_id = c;
                ubx_checksum(c);
                gpsStep++;
                //         mySerial.print("3");
                break;
            }
            case 4:
            {
                meslenL = c;
                ubx_checksum(c);
                gpsStep++;
                //           mySerial.print("ml");
                break;
            }
            case 5:
            {
                meslenH = c;
                ubx_checksum(c);
                gpsStep++;
                meslen = 0xFF & meslenL;
                meslen |= meslenH << 8;
                count = 0;
                //          mySerial.print("mh");
                break;
            }
            case 6:
            {
                message[count] = c;
                ubx_checksum(c);
                count++;
                if (count == meslen)
                {
                    gpsStep++;
                    count = 0;
                }
                break;
            }
            case 7:
            {
                CK_AU = c;
                gpsStep++;
                break;
            }
            case 8:
            {
                CK_BU = c;
                if (CK_A == CK_AU && CK_B == CK_BU) //сравнение контрольной суммы
                {
                    gotUBX = true;
                }
                //    clearVars();
                break;
            }
        }
    }
}

/**
 * \brief UBX-decoder
 */
void decodeUBX(void)
{
    if (UBX_class == 0x01)
    {
        switch (UBX_id)
        {
            case 0x02:  //NAV-POSLLH
            {
                longitude = 0xFF & message[7];       //долгота
                longitude = longitude << 8;
                longitude |= message[6];
                longitude = longitude << 8;
                longitude |= message[5];
                longitude = longitude << 8;
                longitude |= message[4];
                longitudef = longitude / 10000000.0;

                latitude = 0xFF & message[11];       //широта
                latitude = latitude << 8;
                latitude |= message[10];
                latitude = latitude << 8;
                latitude |= message[9];
                latitude = latitude << 8;
                latitude |= message[8];
                latitudef = latitude / 10000000.0;

                height = 0xFF & message[19];         //высота
                height = height << 8;
                height |= message[18];
                height = height << 8;
                height |= message[17];
                height = height << 8;
                height |= message[16];
                heightf = height / 1000.0;

                POSLLH = true;
                break;
            }
            case 0x12:  //NAV-VELNED
            {
                speed3 = 0xFF & message[19];        //скорость
                speed3 = speed3 << 8;
                speed3 |= message[18];
                speed3 = speed3 << 8;
                speed3 |= message[17];
                speed3 = speed3 << 8;
                speed3 |= message[16];
                speed3f = speed3 / 100.0;

                VELNED = true;
                break;
            }
            case 0x06:  // NAV-SOL
            {
                NumSV = message[47];          //кол-во спутников в решении
                FixType |= message[10];        //тип фикса
                //     mySerial.print(message[47]);

                SOL = true;
                break;
            }
        }
    }
}
/**
* \brief Function output data
*/
void sendGPS(void)
{
    mySerial.print("A");
    mySerial.print(longitudef, 5);
    mySerial.print("  B");
    mySerial.print(latitudef, 5);
    mySerial.print("  C");
    mySerial.print(heightf, 3);
    mySerial.print("  D");
    mySerial.print(speed3f, 3);
    mySerial.print("  E");
    mySerial.print(NumSV);
    mySerial.print("  F");
    mySerial.println(FixType);
    longitude = 0;
    latitude = 0;
    height = 0;
    speed3 = 0;
    NumSV = 0;
    FixType = 0;
}
/**
* \brief Data cleansing
*/
void clearVars(void)
{
    gpsStep = 0;
    UBX_id = 0;
    UBX_class = 0;
    meslen = 0;
    count = 0;
    CK_AU = 0;
    CK_BU = 0;
    CK_A = 0;
    CK_B = 0;
    memset(message, 0, 60);
}
/**
 *  \brief Starts only 1 time after reset
 *  \author volodink
 */
void setup() {
    Serial.begin(57600); /**< setup hardware serial for GPS side */
    mySerial.begin(9600);/**< setup hardware serial for GPS side */
}
/**
 *  \brief Running in the infinite loop
 *  \author volodink
 */
void loop()
{
    getUBX();
    if (gotUBX == true)
    {
        mySerial.print("");
        decodeUBX();
        if (POSLLH == 1 && VELNED == 1)
        {
            sendGPS();
            POSLLH = 0;
            VELNED = 0;
            SOL = 0;
        }
        clearVars();
        gotUBX = false;
    }
<commit_msg>Update ubx_decoder.cpp<commit_after>#include <AltSoftSerial.h>
/**
 *  \brief Software serial port object
 *  \author volodink
 */
AltSoftSerial mySerial;

int c = 0; /**< The variable which is assigned received GPS data
 * for later comparison in getUBX
 */
uint8_t message[60]; /**< The maximum Byte Offset */
/**
 * The first argument to calculate the checksum
 */
uint8_t CK_A = 0, CK_B = 0;
/**< The second argument to calculate the checksum */
/**
 * The first argument to comparison the checksum
 */
uint8_t CK_AU = 0, CK_BU = 0; /**< The second argument to comparison the checksum */
int gpsStep = 0; /**< If the data suits us, this parameter makes the step */
uint8_t UBX_id = 0; /**< Message ID */
uint8_t UBX_class = 0; /**< Message class */
uint8_t meslenL = 0;
uint8_t meslenH = 0;
int16_t meslen = 0;
int count = 0;
boolean gotUBX = false; /**< The parameter which checks getting data */
boolean POSLLH = 0; /**< Geodetic Position Solution; This message outputs
 * the Geodetic position in the currently selected Ellipsoid.
 */
boolean SVINFO = 0;/**< Space Vehicle Information */
boolean SOL = 0;/**< Navigation Solution Information; This message combines Position,
 * velocity and time solution in ECEF, including accuracy figures
 */
boolean VELNED = 0;/**< Velocity Solution in NED */
char GPSdata[40];
long int longitude; /**< Longitude */
float longitudef; /**< Output longitude */
long int latitude; /**< Latitude */
float latitudef; /**< Output latitude */
long int height; /**< Height */
float heightf; /**< Output height */
long int speed3; /**< Longitude */
float speed3f; /**< Speed */
/**
 * GPSfix Type, range 0..5;
 * Is a measure of the communication
 * required for a GPS receiver to acquire
 * satellite signals and navigation data
 */
short int FixType;
short int NumSV; /**< Number of SVs used in Nav Solution */
/**
 * \brief uBlox checksum algorithm
 * \param ubx_data Contains the data over
 * which the checksum is to be calculated.
 */
void ubx_checksum(byte ubx_data) //рассчет контрольной суммы
{
    CK_A += ubx_data;
    CK_B += CK_A;
}
/**
 * \brief Getting and comparing data
 */
void getUBX(void) //Получаем пакет и делаем с ним штуки
{
    if (Serial.available())
    {
        uint8_t c = Serial.read();
        switch (gpsStep)
        {
            case 0:
            {
                if (c == 0xB5){
                    gpsStep++;
                    //         mySerial.print("0");
                }
                break;
            }
            case 1:
            {
                if (c == 0x62){
                    gpsStep++;
                    //          mySerial.print("1");
                }
                else{
                    gpsStep = 0;
                    //        mySerial.println("not62");
                }
                break;
            }
            case 2:
            {
                UBX_class = c;
                ubx_checksum(c);
                gpsStep++;
                //        mySerial.print("2");
                break;
            }
            case 3:
            {
                UBX_id = c;
                ubx_checksum(c);
                gpsStep++;
                //         mySerial.print("3");
                break;
            }
            case 4:
            {
                meslenL = c;
                ubx_checksum(c);
                gpsStep++;
                //           mySerial.print("ml");
                break;
            }
            case 5:
            {
                meslenH = c;
                ubx_checksum(c);
                gpsStep++;
                meslen = 0xFF & meslenL;
                meslen |= meslenH << 8;
                count = 0;
                //          mySerial.print("mh");
                break;
            }
            case 6:
            {
                message[count] = c;
                ubx_checksum(c);
                count++;
                if (count == meslen)
                {
                    gpsStep++;
                    count = 0;
                }
                break;
            }
            case 7:
            {
                CK_AU = c;
                gpsStep++;
                break;
            }
            case 8:
            {
                CK_BU = c;
                if (CK_A == CK_AU && CK_B == CK_BU) //сравнение контрольной суммы
                {
                    gotUBX = true;
                }
                //    clearVars();
                break;
            }
        }
    }
}

/**
 * \brief UBX-decoder
 */
void decodeUBX(void)
{
    if (UBX_class == 0x01)
    {
        switch (UBX_id)
        {
            case 0x02:  //NAV-POSLLH
            {
                longitude = 0xFF & message[7];       //долгота
                longitude = longitude << 8;
                longitude |= message[6];
                longitude = longitude << 8;
                longitude |= message[5];
                longitude = longitude << 8;
                longitude |= message[4];
                longitudef = longitude / 10000000.0;

                latitude = 0xFF & message[11];       //широта
                latitude = latitude << 8;
                latitude |= message[10];
                latitude = latitude << 8;
                latitude |= message[9];
                latitude = latitude << 8;
                latitude |= message[8];
                latitudef = latitude / 10000000.0;

                height = 0xFF & message[19];         //высота
                height = height << 8;
                height |= message[18];
                height = height << 8;
                height |= message[17];
                height = height << 8;
                height |= message[16];
                heightf = height / 1000.0;

                POSLLH = true;
                break;
            }
            case 0x12:  //NAV-VELNED
            {
                speed3 = 0xFF & message[19];        //скорость
                speed3 = speed3 << 8;
                speed3 |= message[18];
                speed3 = speed3 << 8;
                speed3 |= message[17];
                speed3 = speed3 << 8;
                speed3 |= message[16];
                speed3f = speed3 / 100.0;

                VELNED = true;
                break;
            }
            case 0x06:  // NAV-SOL
            {
                NumSV = message[47];          //кол-во спутников в решении
                FixType |= message[10];        //тип фикса
                //     mySerial.print(message[47]);

                SOL = true;
                break;
            }
        }
    }
}
/**
* \brief Function output data
*/
void sendGPS(void)
{
    mySerial.print("A");
    mySerial.print(longitudef, 5);
    mySerial.print("  B");
    mySerial.print(latitudef, 5);
    mySerial.print("  C");
    mySerial.print(heightf, 3);
    mySerial.print("  D");
    mySerial.print(speed3f, 3);
    mySerial.print("  E");
    mySerial.print(NumSV);
    mySerial.print("  F");
    mySerial.println(FixType);
    longitude = 0;
    latitude = 0;
    height = 0;
    speed3 = 0;
    NumSV = 0;
    FixType = 0;
}
/**
* \brief Data cleansing
*/
void clearVars(void)
{
    gpsStep = 0;
    UBX_id = 0;
    UBX_class = 0;
    meslen = 0;
    count = 0;
    CK_AU = 0;
    CK_BU = 0;
    CK_A = 0;
    CK_B = 0;
    memset(message, 0, 60);
}
/**
 *  \brief Starts only 1 time after reset
 *  \author volodink
 */
void setup() {
    Serial.begin(57600); /**< setup hardware serial for GPS side */
    mySerial.begin(9600);/**< setup hardware serial for GPS side */
}
/**
 *  \brief Running in the infinite loop
 *  \author volodink
 */
void loop()
{
    getUBX();
    if (gotUBX == true)
    {
        mySerial.print("");
        decodeUBX();
        if (POSLLH == 1 && VELNED == 1)
        {
            sendGPS();
            POSLLH = 0;
            VELNED = 0;
            SOL = 0;
        }
        clearVars();
        gotUBX = false;
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "script/sign.h"

#include "key.h"
#include "keystore.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
#include "script/standard.h"
#include "uint256.h"
#include "mvf-core-globals.h"  // MVF-Core added

#include <boost/foreach.hpp>

using namespace std;

typedef std::vector<unsigned char> valtype;

TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {}

bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode) const
{
    CKey key;
    if (!keystore->GetKey(address, key))
        return false;

    // MVF-Core begin CSIG
    uint256 hash;
    if (isMVFHardForkActive)
        hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, FinalForkId);
    else
        hash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
    // MVF-Core end

    if (!key.Sign(hash, vchSig))
        return false;
    vchSig.push_back((unsigned char)nHashType);
    return true;
}

static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
{
    vector<unsigned char> vchSig;
    if (!creator.CreateSig(vchSig, address, scriptCode))
        return false;
    scriptSigRet << vchSig;
    return true;
}

static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
{
    int nSigned = 0;
    int nRequired = multisigdata.front()[0];
    for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
    {
        const valtype& pubkey = multisigdata[i];
        CKeyID keyID = CPubKey(pubkey).GetID();
        if (Sign1(keyID, creator, scriptCode, scriptSigRet))
            ++nSigned;
    }
    return nSigned==nRequired;
}

/**
 * Sign scriptPubKey using signature made with creator.
 * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
 * unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
 * Returns false if scriptPubKey could not be completely satisfied.
 */
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
                     CScript& scriptSigRet, txnouttype& whichTypeRet)
{
    scriptSigRet.clear();

    vector<valtype> vSolutions;
    if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
        return false;

    CKeyID keyID;
    switch (whichTypeRet)
    {
    case TX_NONSTANDARD:
    case TX_NULL_DATA:
        return false;
    case TX_PUBKEY:
        keyID = CPubKey(vSolutions[0]).GetID();
        return Sign1(keyID, creator, scriptPubKey, scriptSigRet);
    case TX_PUBKEYHASH:
        keyID = CKeyID(uint160(vSolutions[0]));
        if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet))
            return false;
        else
        {
            CPubKey vch;
            creator.KeyStore().GetPubKey(keyID, vch);
            scriptSigRet << ToByteVector(vch);
        }
        return true;
    case TX_SCRIPTHASH:
        return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet);

    case TX_MULTISIG:
        scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
        return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet));
    }
    return false;
}

bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig)
{
    txnouttype whichType;
    if (!SignStep(creator, fromPubKey, scriptSig, whichType))
        return false;

    if (whichType == TX_SCRIPTHASH)
    {
        // Solver returns the subscript that need to be evaluated;
        // the final scriptSig is the signatures from that
        // and then the serialized subscript:
        CScript subscript = scriptSig;

        txnouttype subType;
        bool fSolved =
            SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH;
        // Append serialized subscript whether or not it is completely signed:
        scriptSig << valtype(subscript.begin(), subscript.end());
        if (!fSolved) return false;
    }

    // Test solution
    return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
}

bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
    assert(nIn < txTo.vin.size());
    CTxIn& txin = txTo.vin[nIn];

    CTransaction txToConst(txTo);
    TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType);

    return ProduceSignature(creator, fromPubKey, txin.scriptSig);
}

bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
    assert(nIn < txTo.vin.size());
    CTxIn& txin = txTo.vin[nIn];
    assert(txin.prevout.n < txFrom.vout.size());
    const CTxOut& txout = txFrom.vout[txin.prevout.n];

    return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
}

static CScript PushAll(const vector<valtype>& values)
{
    CScript result;
    BOOST_FOREACH(const valtype& v, values)
        result << v;
    return result;
}

static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
                               const vector<valtype>& vSolutions,
                               const vector<valtype>& sigs1, const vector<valtype>& sigs2)
{
    // Combine all the signatures we've got:
    set<valtype> allsigs;
    BOOST_FOREACH(const valtype& v, sigs1)
    {
        if (!v.empty())
            allsigs.insert(v);
    }
    BOOST_FOREACH(const valtype& v, sigs2)
    {
        if (!v.empty())
            allsigs.insert(v);
    }

    // Build a map of pubkey -> signature by matching sigs to pubkeys:
    assert(vSolutions.size() > 1);
    unsigned int nSigsRequired = vSolutions.front()[0];
    unsigned int nPubKeys = vSolutions.size()-2;
    map<valtype, valtype> sigs;
    BOOST_FOREACH(const valtype& sig, allsigs)
    {
        for (unsigned int i = 0; i < nPubKeys; i++)
        {
            const valtype& pubkey = vSolutions[i+1];
            if (sigs.count(pubkey))
                continue; // Already got a sig for this pubkey

            if (checker.CheckSig(sig, pubkey, scriptPubKey))
            {
                sigs[pubkey] = sig;
                break;
            }
        }
    }
    // Now build a merged CScript:
    unsigned int nSigsHave = 0;
    CScript result; result << OP_0; // pop-one-too-many workaround
    for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
    {
        if (sigs.count(vSolutions[i+1]))
        {
            result << sigs[vSolutions[i+1]];
            ++nSigsHave;
        }
    }
    // Fill any missing with OP_0:
    for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
        result << OP_0;

    return result;
}

static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
                                 const txnouttype txType, const vector<valtype>& vSolutions,
                                 vector<valtype>& sigs1, vector<valtype>& sigs2)
{
    switch (txType)
    {
    case TX_NONSTANDARD:
    case TX_NULL_DATA:
        // Don't know anything about this, assume bigger one is correct:
        if (sigs1.size() >= sigs2.size())
            return PushAll(sigs1);
        return PushAll(sigs2);
    case TX_PUBKEY:
    case TX_PUBKEYHASH:
        // Signatures are bigger than placeholders or empty scripts:
        if (sigs1.empty() || sigs1[0].empty())
            return PushAll(sigs2);
        return PushAll(sigs1);
    case TX_SCRIPTHASH:
        if (sigs1.empty() || sigs1.back().empty())
            return PushAll(sigs2);
        else if (sigs2.empty() || sigs2.back().empty())
            return PushAll(sigs1);
        else
        {
            // Recur to combine:
            valtype spk = sigs1.back();
            CScript pubKey2(spk.begin(), spk.end());

            txnouttype txType2;
            vector<vector<unsigned char> > vSolutions2;
            Solver(pubKey2, txType2, vSolutions2);
            sigs1.pop_back();
            sigs2.pop_back();
            CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2);
            result << spk;
            return result;
        }
    case TX_MULTISIG:
        return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2);
    }

    return CScript();
}

CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
                          const CScript& scriptSig1, const CScript& scriptSig2)
{
    TransactionSignatureChecker checker(&txTo, nIn);
    return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2);
}

CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
                          const CScript& scriptSig1, const CScript& scriptSig2)
{
    txnouttype txType;
    vector<vector<unsigned char> > vSolutions;
    Solver(scriptPubKey, txType, vSolutions);

    vector<valtype> stack1;
    EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
    vector<valtype> stack2;
    EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());

    return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
}

namespace {
/** Dummy signature checker which accepts all signatures. */
class DummySignatureChecker : public BaseSignatureChecker
{
public:
    DummySignatureChecker() {}

    bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
    {
        return true;
    }
};
const DummySignatureChecker dummyChecker;
}

const BaseSignatureChecker& DummySignatureCreator::Checker() const
{
    return dummyChecker;
}

bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const
{
    // Create a dummy signature that is a valid DER-encoding
    vchSig.assign(72, '\000');
    vchSig[0] = 0x30;
    vchSig[1] = 69;
    vchSig[2] = 0x02;
    vchSig[3] = 33;
    vchSig[4] = 0x01;
    vchSig[4 + 33] = 0x02;
    vchSig[5 + 33] = 32;
    vchSig[6 + 33] = 0x01;
    vchSig[6 + 33 + 32] = SIGHASH_ALL;
    return true;
}
<commit_msg>remove trailing whitespace<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "script/sign.h"

#include "key.h"
#include "keystore.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
#include "script/standard.h"
#include "uint256.h"
#include "mvf-core-globals.h"  // MVF-Core added

#include <boost/foreach.hpp>

using namespace std;

typedef std::vector<unsigned char> valtype;

TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {}

bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode) const
{
    CKey key;
    if (!keystore->GetKey(address, key))
        return false;

    // MVF-Core begin CSIG
    uint256 hash;
    if (isMVFHardForkActive)
        hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, FinalForkId);
    else
        hash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
    // MVF-Core end

    if (!key.Sign(hash, vchSig))
        return false;
    vchSig.push_back((unsigned char)nHashType);
    return true;
}

static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
{
    vector<unsigned char> vchSig;
    if (!creator.CreateSig(vchSig, address, scriptCode))
        return false;
    scriptSigRet << vchSig;
    return true;
}

static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
{
    int nSigned = 0;
    int nRequired = multisigdata.front()[0];
    for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
    {
        const valtype& pubkey = multisigdata[i];
        CKeyID keyID = CPubKey(pubkey).GetID();
        if (Sign1(keyID, creator, scriptCode, scriptSigRet))
            ++nSigned;
    }
    return nSigned==nRequired;
}

/**
 * Sign scriptPubKey using signature made with creator.
 * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
 * unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
 * Returns false if scriptPubKey could not be completely satisfied.
 */
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
                     CScript& scriptSigRet, txnouttype& whichTypeRet)
{
    scriptSigRet.clear();

    vector<valtype> vSolutions;
    if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
        return false;

    CKeyID keyID;
    switch (whichTypeRet)
    {
    case TX_NONSTANDARD:
    case TX_NULL_DATA:
        return false;
    case TX_PUBKEY:
        keyID = CPubKey(vSolutions[0]).GetID();
        return Sign1(keyID, creator, scriptPubKey, scriptSigRet);
    case TX_PUBKEYHASH:
        keyID = CKeyID(uint160(vSolutions[0]));
        if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet))
            return false;
        else
        {
            CPubKey vch;
            creator.KeyStore().GetPubKey(keyID, vch);
            scriptSigRet << ToByteVector(vch);
        }
        return true;
    case TX_SCRIPTHASH:
        return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet);

    case TX_MULTISIG:
        scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
        return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet));
    }
    return false;
}

bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig)
{
    txnouttype whichType;
    if (!SignStep(creator, fromPubKey, scriptSig, whichType))
        return false;

    if (whichType == TX_SCRIPTHASH)
    {
        // Solver returns the subscript that need to be evaluated;
        // the final scriptSig is the signatures from that
        // and then the serialized subscript:
        CScript subscript = scriptSig;

        txnouttype subType;
        bool fSolved =
            SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH;
        // Append serialized subscript whether or not it is completely signed:
        scriptSig << valtype(subscript.begin(), subscript.end());
        if (!fSolved) return false;
    }

    // Test solution
    return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
}

bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
    assert(nIn < txTo.vin.size());
    CTxIn& txin = txTo.vin[nIn];

    CTransaction txToConst(txTo);
    TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType);

    return ProduceSignature(creator, fromPubKey, txin.scriptSig);
}

bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
    assert(nIn < txTo.vin.size());
    CTxIn& txin = txTo.vin[nIn];
    assert(txin.prevout.n < txFrom.vout.size());
    const CTxOut& txout = txFrom.vout[txin.prevout.n];

    return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
}

static CScript PushAll(const vector<valtype>& values)
{
    CScript result;
    BOOST_FOREACH(const valtype& v, values)
        result << v;
    return result;
}

static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
                               const vector<valtype>& vSolutions,
                               const vector<valtype>& sigs1, const vector<valtype>& sigs2)
{
    // Combine all the signatures we've got:
    set<valtype> allsigs;
    BOOST_FOREACH(const valtype& v, sigs1)
    {
        if (!v.empty())
            allsigs.insert(v);
    }
    BOOST_FOREACH(const valtype& v, sigs2)
    {
        if (!v.empty())
            allsigs.insert(v);
    }

    // Build a map of pubkey -> signature by matching sigs to pubkeys:
    assert(vSolutions.size() > 1);
    unsigned int nSigsRequired = vSolutions.front()[0];
    unsigned int nPubKeys = vSolutions.size()-2;
    map<valtype, valtype> sigs;
    BOOST_FOREACH(const valtype& sig, allsigs)
    {
        for (unsigned int i = 0; i < nPubKeys; i++)
        {
            const valtype& pubkey = vSolutions[i+1];
            if (sigs.count(pubkey))
                continue; // Already got a sig for this pubkey

            if (checker.CheckSig(sig, pubkey, scriptPubKey))
            {
                sigs[pubkey] = sig;
                break;
            }
        }
    }
    // Now build a merged CScript:
    unsigned int nSigsHave = 0;
    CScript result; result << OP_0; // pop-one-too-many workaround
    for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
    {
        if (sigs.count(vSolutions[i+1]))
        {
            result << sigs[vSolutions[i+1]];
            ++nSigsHave;
        }
    }
    // Fill any missing with OP_0:
    for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
        result << OP_0;

    return result;
}

static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
                                 const txnouttype txType, const vector<valtype>& vSolutions,
                                 vector<valtype>& sigs1, vector<valtype>& sigs2)
{
    switch (txType)
    {
    case TX_NONSTANDARD:
    case TX_NULL_DATA:
        // Don't know anything about this, assume bigger one is correct:
        if (sigs1.size() >= sigs2.size())
            return PushAll(sigs1);
        return PushAll(sigs2);
    case TX_PUBKEY:
    case TX_PUBKEYHASH:
        // Signatures are bigger than placeholders or empty scripts:
        if (sigs1.empty() || sigs1[0].empty())
            return PushAll(sigs2);
        return PushAll(sigs1);
    case TX_SCRIPTHASH:
        if (sigs1.empty() || sigs1.back().empty())
            return PushAll(sigs2);
        else if (sigs2.empty() || sigs2.back().empty())
            return PushAll(sigs1);
        else
        {
            // Recur to combine:
            valtype spk = sigs1.back();
            CScript pubKey2(spk.begin(), spk.end());

            txnouttype txType2;
            vector<vector<unsigned char> > vSolutions2;
            Solver(pubKey2, txType2, vSolutions2);
            sigs1.pop_back();
            sigs2.pop_back();
            CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2);
            result << spk;
            return result;
        }
    case TX_MULTISIG:
        return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2);
    }

    return CScript();
}

CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
                          const CScript& scriptSig1, const CScript& scriptSig2)
{
    TransactionSignatureChecker checker(&txTo, nIn);
    return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2);
}

CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
                          const CScript& scriptSig1, const CScript& scriptSig2)
{
    txnouttype txType;
    vector<vector<unsigned char> > vSolutions;
    Solver(scriptPubKey, txType, vSolutions);

    vector<valtype> stack1;
    EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
    vector<valtype> stack2;
    EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());

    return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
}

namespace {
/** Dummy signature checker which accepts all signatures. */
class DummySignatureChecker : public BaseSignatureChecker
{
public:
    DummySignatureChecker() {}

    bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
    {
        return true;
    }
};
const DummySignatureChecker dummyChecker;
}

const BaseSignatureChecker& DummySignatureCreator::Checker() const
{
    return dummyChecker;
}

bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const
{
    // Create a dummy signature that is a valid DER-encoding
    vchSig.assign(72, '\000');
    vchSig[0] = 0x30;
    vchSig[1] = 69;
    vchSig[2] = 0x02;
    vchSig[3] = 33;
    vchSig[4] = 0x01;
    vchSig[4 + 33] = 0x02;
    vchSig[5 + 33] = 32;
    vchSig[6 + 33] = 0x01;
    vchSig[6 + 33 + 32] = SIGHASH_ALL;
    return true;
}
<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include "tensorflow/compiler/mlir/tensorflow/transforms/bridge.h"

#include <memory>

#include "mlir/IR/Module.h"  // TF:llvm-project
#include "mlir/Pass/PassManager.h"  // TF:llvm-project
#include "mlir/Transforms/Passes.h"  // TF:llvm-project
#include "tensorflow/compiler/mlir/tensorflow/transforms/passes.h"
#include "tensorflow/compiler/mlir/tensorflow/utils/bridge_logger.h"
#include "tensorflow/compiler/mlir/tensorflow/utils/error_util.h"

namespace mlir {
namespace TFTPU {
namespace {
void AddGraphExportLoweringPasses(OpPassManager &pm) {
  pm.addNestedPass<FuncOp>(CreateFunctionalToExecutorDialectConversionPass());
  pm.addNestedPass<FuncOp>(CreateBreakUpIslandsPass());
  pm.addNestedPass<FuncOp>(TFDevice::CreateReplicateToIslandPass());
  pm.addNestedPass<FuncOp>(CreateBreakUpIslandsPass());
  pm.addNestedPass<FuncOp>(TFDevice::CreateLaunchToDeviceAttributePass());
}

tensorflow::Status RunTPUBridge(
    ModuleOp module, bool enable_logging,
    llvm::function_ref<void(OpPassManager &pm)> pipeline_builder) {
  PassManager bridge(module.getContext());

  // Add logger to bridge passmanager.
  if (enable_logging)
    bridge.enableIRPrinting(std::make_unique<tensorflow::BridgeLoggerConfig>());

  // Populate a passmanager with the list of passes that implement the bridge.
  pipeline_builder(bridge);

  // Add set of passes to lower back to graph (from tf_executor).
  AddGraphExportLoweringPasses(bridge);

  // Run the bridge on the module, in case of failure, the `diag_handler`
  // converts MLIR errors emitted to the MLIRContext into a tensorflow::Status.
  mlir::StatusScopedDiagnosticHandler diag_handler(module.getContext());
  LogicalResult result = bridge.run(module);
  (void)result;
  return diag_handler.ConsumeStatus();
}
}  // namespace

void CreateTPUBridgePipeline(OpPassManager &pm) {
  // Run island coarsening before shape inference to allow more exact shape
  // inference using constant folding within islands.
  pm.addNestedPass<FuncOp>(tf_executor::CreateTFExecutorIslandCoarseningPass());
  // Run shape inference so that tf_executor/tf_device ops created later will
  // likely to inherit more concrete types.
  pm.addPass(TF::CreateTFShapeInferencePass());
  OpPassManager &func_pm = pm.nest<FuncOp>();
  func_pm.addPass(CreateTPUClusterFormationPass());
  func_pm.addPass(createCanonicalizerPass());
  // Place DecomposeResourceOpsPass before TFExecutorConstantSinking pass
  // because DecomposeResourceOpsPass uses pattern rewriter which hoists
  // changed constants out of tf_device.Launch.
  func_pm.addPass(TFDevice::CreateDecomposeResourceOpsPass());

  // Run another shape inference pass because resource decomposition might have
  // created new partial types.
  pm.addPass(TF::CreateTFShapeInferencePass());
  pm.addNestedPass<FuncOp>(tf_executor::CreateTFExecutorConstantSinkingPass());
  pm.addPass(TFDevice::CreateResourceOpLiftingPass());
  pm.addPass(TF::CreateResourceDeviceInferencePass());
  pm.addPass(TFDevice::CreateClusterOutliningPass());
  pm.addPass(CreateTPUDynamicPaddingMapperPass());
  pm.addPass(TFDevice::CreateAnnotateParameterReplicationPass());
  pm.addPass(CreateTPURewritePass());
  pm.addNestedPass<FuncOp>(TFDevice::CreateReplicateInvariantOpHoistingPass());
  pm.addNestedPass<FuncOp>(CreateTPUDynamicLayoutPass());
  pm.addNestedPass<FuncOp>(CreateTPUMergeVariablesWithExecutePass());
  pm.addPass(CreateTPUVariableReformattingPass());
}

void CreateTPUBridgePipelineV1(OpPassManager &pm) {
  // For V1 compatibility, we process a module where the graph does not have
  // feeds and fetched. We extract first the TPU computation in a submodule,
  // where it'll be in a function with args and returned values, much more like
  // a TF v2 module. We can then run the usual pipeline on this nested module.
  // Afterward we inline back in the parent module and delete the nested one.
  pm.addPass(tf_executor::CreateTFExecutorTPUV1IslandCoarseningPass());
  pm.addPass(tf_executor::CreateTFExecutorTPUV1IslandOutliningPass());
  OpPassManager &nested_module = pm.nest<ModuleOp>();
  CreateTPUBridgePipeline(nested_module);
  pm.addPass(tf_executor::CreateTFExecutorTPUV1IslandInliningPass());
}

tensorflow::Status TPUBridge(ModuleOp module, bool enable_logging) {
  return RunTPUBridge(module, enable_logging, CreateTPUBridgePipeline);
}
tensorflow::Status TPUBridgeV1Compat(ModuleOp module, bool enable_logging) {
  return RunTPUBridge(module, enable_logging, CreateTPUBridgePipelineV1);
}

}  // namespace TFTPU

namespace TF {

tensorflow::Status RunBridgeWithStandardPipeline(ModuleOp module,
                                                 bool enable_logging,
                                                 bool enable_inliner) {
  PassManager bridge(module.getContext());

  // Add logger to bridge passmanager.
  if (enable_logging)
    bridge.enableIRPrinting(std::make_unique<tensorflow::BridgeLoggerConfig>());

  StandardPipelineOptions pipeline_options;
  pipeline_options.enable_inliner.setValue(enable_inliner);
  CreateTFStandardPipeline(bridge, pipeline_options);
  mlir::StatusScopedDiagnosticHandler diag_handler(module.getContext());
  LogicalResult result = bridge.run(module);
  (void)result;
  return diag_handler.ConsumeStatus();
}

}  // namespace TF
}  // namespace mlir
<commit_msg>Print the whole module in the bridge logging<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include "tensorflow/compiler/mlir/tensorflow/transforms/bridge.h"

#include <memory>

#include "mlir/IR/Module.h"  // TF:llvm-project
#include "mlir/Pass/PassManager.h"  // TF:llvm-project
#include "mlir/Transforms/Passes.h"  // TF:llvm-project
#include "tensorflow/compiler/mlir/tensorflow/transforms/passes.h"
#include "tensorflow/compiler/mlir/tensorflow/utils/bridge_logger.h"
#include "tensorflow/compiler/mlir/tensorflow/utils/error_util.h"

namespace mlir {
namespace TFTPU {
namespace {
void AddGraphExportLoweringPasses(OpPassManager &pm) {
  pm.addNestedPass<FuncOp>(CreateFunctionalToExecutorDialectConversionPass());
  pm.addNestedPass<FuncOp>(CreateBreakUpIslandsPass());
  pm.addNestedPass<FuncOp>(TFDevice::CreateReplicateToIslandPass());
  pm.addNestedPass<FuncOp>(CreateBreakUpIslandsPass());
  pm.addNestedPass<FuncOp>(TFDevice::CreateLaunchToDeviceAttributePass());
}

tensorflow::Status RunTPUBridge(
    ModuleOp module, bool enable_logging,
    llvm::function_ref<void(OpPassManager &pm)> pipeline_builder) {
  PassManager bridge(module.getContext());

  // Add logger to bridge passmanager.
  if (enable_logging)
    bridge.enableIRPrinting(std::make_unique<tensorflow::BridgeLoggerConfig>());

  // Populate a passmanager with the list of passes that implement the bridge.
  pipeline_builder(bridge);

  // Add set of passes to lower back to graph (from tf_executor).
  AddGraphExportLoweringPasses(bridge);

  // Run the bridge on the module, in case of failure, the `diag_handler`
  // converts MLIR errors emitted to the MLIRContext into a tensorflow::Status.
  mlir::StatusScopedDiagnosticHandler diag_handler(module.getContext());
  LogicalResult result = bridge.run(module);
  (void)result;
  return diag_handler.ConsumeStatus();
}
}  // namespace

void CreateTPUBridgePipeline(OpPassManager &pm) {
  // Run island coarsening before shape inference to allow more exact shape
  // inference using constant folding within islands.
  pm.addNestedPass<FuncOp>(tf_executor::CreateTFExecutorIslandCoarseningPass());
  // Run shape inference so that tf_executor/tf_device ops created later will
  // likely to inherit more concrete types.
  pm.addPass(TF::CreateTFShapeInferencePass());
  OpPassManager &func_pm = pm.nest<FuncOp>();
  func_pm.addPass(CreateTPUClusterFormationPass());
  func_pm.addPass(createCanonicalizerPass());
  // Place DecomposeResourceOpsPass before TFExecutorConstantSinking pass
  // because DecomposeResourceOpsPass uses pattern rewriter which hoists
  // changed constants out of tf_device.Launch.
  func_pm.addPass(TFDevice::CreateDecomposeResourceOpsPass());

  // Run another shape inference pass because resource decomposition might have
  // created new partial types.
  pm.addPass(TF::CreateTFShapeInferencePass());
  pm.addNestedPass<FuncOp>(tf_executor::CreateTFExecutorConstantSinkingPass());
  pm.addPass(TFDevice::CreateResourceOpLiftingPass());
  pm.addPass(TF::CreateResourceDeviceInferencePass());
  pm.addPass(TFDevice::CreateClusterOutliningPass());
  pm.addPass(CreateTPUDynamicPaddingMapperPass());
  pm.addPass(TFDevice::CreateAnnotateParameterReplicationPass());
  pm.addPass(CreateTPURewritePass());
  pm.addNestedPass<FuncOp>(TFDevice::CreateReplicateInvariantOpHoistingPass());
  pm.addNestedPass<FuncOp>(CreateTPUDynamicLayoutPass());
  pm.addNestedPass<FuncOp>(CreateTPUMergeVariablesWithExecutePass());
  pm.addPass(CreateTPUVariableReformattingPass());
}

void CreateTPUBridgePipelineV1(OpPassManager &pm) {
  // For V1 compatibility, we process a module where the graph does not have
  // feeds and fetched. We extract first the TPU computation in a submodule,
  // where it'll be in a function with args and returned values, much more like
  // a TF v2 module. We can then run the usual pipeline on this nested module.
  // Afterward we inline back in the parent module and delete the nested one.
  pm.addPass(tf_executor::CreateTFExecutorTPUV1IslandCoarseningPass());
  pm.addPass(tf_executor::CreateTFExecutorTPUV1IslandOutliningPass());
  OpPassManager &nested_module = pm.nest<ModuleOp>();
  CreateTPUBridgePipeline(nested_module);
  pm.addPass(tf_executor::CreateTFExecutorTPUV1IslandInliningPass());
}

tensorflow::Status TPUBridge(ModuleOp module, bool enable_logging) {
  return RunTPUBridge(module, enable_logging, CreateTPUBridgePipeline);
}
tensorflow::Status TPUBridgeV1Compat(ModuleOp module, bool enable_logging) {
  return RunTPUBridge(module, enable_logging, CreateTPUBridgePipelineV1);
}

}  // namespace TFTPU

namespace TF {

tensorflow::Status RunBridgeWithStandardPipeline(ModuleOp module,
                                                 bool enable_logging,
                                                 bool enable_inliner) {
  PassManager bridge(module.getContext());

  // Add logger to bridge passmanager.
  if (enable_logging) {
    // Print the whole module after each pass, which requires disabling
    // multi-threading as well.
    bridge.disableMultithreading();
    bridge.enableIRPrinting(std::make_unique<tensorflow::BridgeLoggerConfig>(
        /* print_module_scope=*/true));
  }

  StandardPipelineOptions pipeline_options;
  pipeline_options.enable_inliner.setValue(enable_inliner);
  CreateTFStandardPipeline(bridge, pipeline_options);
  mlir::StatusScopedDiagnosticHandler diag_handler(module.getContext());
  LogicalResult result = bridge.run(module);
  (void)result;
  return diag_handler.ConsumeStatus();
}

}  // namespace TF
}  // namespace mlir
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/frame/browser_frame.h"

#include <dwmapi.h>

#include "chrome/browser/browser_list.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/frame/glass_browser_frame_view.h"
#include "chrome/browser/views/frame/opaque_browser_frame_view.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/common/win_util.h"
#include "chrome/views/window_delegate.h"
#include "grit/theme_resources.h"

// static
static const int kClientEdgeThickness = 3;

///////////////////////////////////////////////////////////////////////////////
// BrowserFrame, public:

BrowserFrame::BrowserFrame(BrowserView* browser_view)
    : Window(browser_view),
      browser_view_(browser_view),
      frame_initialized_(false) {
  browser_view_->set_frame(this);
  non_client_view_->SetFrameView(CreateFrameViewForWindow());
}

BrowserFrame::~BrowserFrame() {
}

void BrowserFrame::Init() {
  Window::Init(NULL, gfx::Rect());
}

int BrowserFrame::GetMinimizeButtonOffset() const {
  TITLEBARINFOEX titlebar_info;
  titlebar_info.cbSize = sizeof(TITLEBARINFOEX);
  SendMessage(GetHWND(), WM_GETTITLEBARINFOEX, 0, (WPARAM)&titlebar_info);

  CPoint minimize_button_corner(titlebar_info.rgrect[2].left,
                                titlebar_info.rgrect[2].top);
  MapWindowPoints(HWND_DESKTOP, GetHWND(), &minimize_button_corner, 1);

  return minimize_button_corner.x;
}

gfx::Rect BrowserFrame::GetBoundsForTabStrip(TabStrip* tabstrip) const {
  return browser_frame_view_->GetBoundsForTabStrip(tabstrip);
}

void BrowserFrame::UpdateThrobber(bool running) {
  browser_frame_view_->UpdateThrobber(running);
}

///////////////////////////////////////////////////////////////////////////////
// BrowserFrame, views::WidgetWin overrides:

bool BrowserFrame::AcceleratorPressed(views::Accelerator* accelerator) {
  return browser_view_->AcceleratorPressed(*accelerator);
}

bool BrowserFrame::GetAccelerator(int cmd_id, views::Accelerator* accelerator) {
  return browser_view_->GetAccelerator(cmd_id, accelerator);
}

void BrowserFrame::OnEndSession(BOOL ending, UINT logoff) {
  BrowserList::WindowsSessionEnding();
}

void BrowserFrame::OnEnterSizeMove() {
  browser_view_->WindowMoveOrResizeStarted();
}

void BrowserFrame::OnInitMenuPopup(HMENU menu, UINT position,
                                     BOOL is_system_menu) {
  browser_view_->PrepareToRunSystemMenu(menu);
}

LRESULT BrowserFrame::OnMouseActivate(HWND window, UINT hittest_code,
                                        UINT message) {
  return browser_view_->ActivateAppModalDialog() ? MA_NOACTIVATEANDEAT
                                                 : MA_ACTIVATE;
}

void BrowserFrame::OnMove(const CPoint& point) {
  browser_view_->WindowMoved();
}

void BrowserFrame::OnMoving(UINT param, const RECT* new_bounds) {
  browser_view_->WindowMoved();
}

LRESULT BrowserFrame::OnNCActivate(BOOL active) {
  if (browser_view_->ActivateAppModalDialog())
    return TRUE;

  // Perform first time initialization of the DWM frame insets, only if we're
  // using the native frame.
  if (non_client_view_->UseNativeFrame() && !frame_initialized_) {
    if (browser_view_->IsBrowserTypeNormal()) {
      ::SetWindowPos(GetHWND(), NULL, 0, 0, 0, 0,
                     SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);
      UpdateDWMFrame();
    }
    frame_initialized_ = true;
  }
  browser_view_->ActivationChanged(!!active);
  return Window::OnNCActivate(active);
}

LRESULT BrowserFrame::OnNCCalcSize(BOOL mode, LPARAM l_param) {
  // We don't adjust the client area unless we're a tabbed browser window and
  // are using the native frame.
  if (!non_client_view_->UseNativeFrame() ||
      !browser_view_->IsBrowserTypeNormal() || !mode) {
    return Window::OnNCCalcSize(mode, l_param);
  }

  // In fullscreen mode, we make the whole window client area.
  if (!browser_view_->IsFullscreen()) {
    NCCALCSIZE_PARAMS* params = reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param);
    int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
    params->rgrc[0].left += (border_thickness - kClientEdgeThickness);
    params->rgrc[0].right -= (border_thickness - kClientEdgeThickness);
    params->rgrc[0].bottom -= (border_thickness - kClientEdgeThickness);
  }

  UpdateDWMFrame();

  SetMsgHandled(TRUE);
  return 0;
}

LRESULT BrowserFrame::OnNCHitTest(const CPoint& pt) {
  // Only do DWM hit-testing when we are using the native frame.
  if (non_client_view_->UseNativeFrame()) {
    LRESULT result;
    if (DwmDefWindowProc(GetHWND(), WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y),
                         &result)) {
      return result;
    }
  }
  return Window::OnNCHitTest(pt);
}

///////////////////////////////////////////////////////////////////////////////
// BrowserFrame, views::CustomFrameWindow overrides:

int BrowserFrame::GetShowState() const {
  return browser_view_->GetShowState();
}

views::NonClientFrameView* BrowserFrame::CreateFrameViewForWindow() {
  if (non_client_view_->UseNativeFrame())
    browser_frame_view_ = new GlassBrowserFrameView(this, browser_view_);
  else
    browser_frame_view_ = new OpaqueBrowserFrameView(this, browser_view_);
  return browser_frame_view_;
}

void BrowserFrame::UpdateFrameAfterFrameChange() {
  Window::UpdateFrameAfterFrameChange();
  UpdateDWMFrame();
}

///////////////////////////////////////////////////////////////////////////////
// BrowserFrame, private:

void BrowserFrame::UpdateDWMFrame() {
  // Nothing to do yet.
  if (!client_view())
    return;

  // In fullscreen mode, we don't extend glass into the client area at all,
  // because the GDI-drawn text in the web content composited over it will
  // become semi-transparent over any glass area.
  MARGINS margins = { 0 };
  if (!browser_view_->IsFullscreen()) {
    margins.cxLeftWidth = kClientEdgeThickness + 1;
    margins.cxRightWidth = kClientEdgeThickness + 1;
    margins.cyTopHeight =
        GetBoundsForTabStrip(browser_view_->tabstrip()).bottom();
    margins.cyBottomHeight = kClientEdgeThickness + 1;
  }
  DwmExtendFrameIntoClientArea(GetHWND(), &margins);
}

<commit_msg>Fix a small issue changing back to glass frame from opaque where the<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/frame/browser_frame.h"

#include <dwmapi.h>

#include "chrome/browser/browser_list.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/browser/views/frame/glass_browser_frame_view.h"
#include "chrome/browser/views/frame/opaque_browser_frame_view.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/common/win_util.h"
#include "chrome/views/window_delegate.h"
#include "grit/theme_resources.h"

// static
static const int kClientEdgeThickness = 3;

///////////////////////////////////////////////////////////////////////////////
// BrowserFrame, public:

BrowserFrame::BrowserFrame(BrowserView* browser_view)
    : Window(browser_view),
      browser_view_(browser_view),
      frame_initialized_(false) {
  browser_view_->set_frame(this);
  non_client_view_->SetFrameView(CreateFrameViewForWindow());
}

BrowserFrame::~BrowserFrame() {
}

void BrowserFrame::Init() {
  Window::Init(NULL, gfx::Rect());
}

int BrowserFrame::GetMinimizeButtonOffset() const {
  TITLEBARINFOEX titlebar_info;
  titlebar_info.cbSize = sizeof(TITLEBARINFOEX);
  SendMessage(GetHWND(), WM_GETTITLEBARINFOEX, 0, (WPARAM)&titlebar_info);

  CPoint minimize_button_corner(titlebar_info.rgrect[2].left,
                                titlebar_info.rgrect[2].top);
  MapWindowPoints(HWND_DESKTOP, GetHWND(), &minimize_button_corner, 1);

  return minimize_button_corner.x;
}

gfx::Rect BrowserFrame::GetBoundsForTabStrip(TabStrip* tabstrip) const {
  return browser_frame_view_->GetBoundsForTabStrip(tabstrip);
}

void BrowserFrame::UpdateThrobber(bool running) {
  browser_frame_view_->UpdateThrobber(running);
}

///////////////////////////////////////////////////////////////////////////////
// BrowserFrame, views::WidgetWin overrides:

bool BrowserFrame::AcceleratorPressed(views::Accelerator* accelerator) {
  return browser_view_->AcceleratorPressed(*accelerator);
}

bool BrowserFrame::GetAccelerator(int cmd_id, views::Accelerator* accelerator) {
  return browser_view_->GetAccelerator(cmd_id, accelerator);
}

void BrowserFrame::OnEndSession(BOOL ending, UINT logoff) {
  BrowserList::WindowsSessionEnding();
}

void BrowserFrame::OnEnterSizeMove() {
  browser_view_->WindowMoveOrResizeStarted();
}

void BrowserFrame::OnInitMenuPopup(HMENU menu, UINT position,
                                     BOOL is_system_menu) {
  browser_view_->PrepareToRunSystemMenu(menu);
}

LRESULT BrowserFrame::OnMouseActivate(HWND window, UINT hittest_code,
                                        UINT message) {
  return browser_view_->ActivateAppModalDialog() ? MA_NOACTIVATEANDEAT
                                                 : MA_ACTIVATE;
}

void BrowserFrame::OnMove(const CPoint& point) {
  browser_view_->WindowMoved();
}

void BrowserFrame::OnMoving(UINT param, const RECT* new_bounds) {
  browser_view_->WindowMoved();
}

LRESULT BrowserFrame::OnNCActivate(BOOL active) {
  if (browser_view_->ActivateAppModalDialog())
    return TRUE;

  // Perform first time initialization of the DWM frame insets, only if we're
  // using the native frame.
  if (non_client_view_->UseNativeFrame() && !frame_initialized_) {
    if (browser_view_->IsBrowserTypeNormal()) {
      ::SetWindowPos(GetHWND(), NULL, 0, 0, 0, 0,
                     SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);
      UpdateDWMFrame();
    }
    frame_initialized_ = true;
  }
  browser_view_->ActivationChanged(!!active);
  return Window::OnNCActivate(active);
}

LRESULT BrowserFrame::OnNCCalcSize(BOOL mode, LPARAM l_param) {
  // We don't adjust the client area unless we're a tabbed browser window and
  // are using the native frame.
  if (!non_client_view_->UseNativeFrame() ||
      !browser_view_->IsBrowserTypeNormal() || !mode) {
    return Window::OnNCCalcSize(mode, l_param);
  }

  // In fullscreen mode, we make the whole window client area.
  if (!browser_view_->IsFullscreen()) {
    NCCALCSIZE_PARAMS* params = reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param);
    int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
    params->rgrc[0].left += (border_thickness - kClientEdgeThickness);
    params->rgrc[0].right -= (border_thickness - kClientEdgeThickness);
    params->rgrc[0].bottom -= (border_thickness - kClientEdgeThickness);
  }

  UpdateDWMFrame();

  SetMsgHandled(TRUE);
  return 0;
}

LRESULT BrowserFrame::OnNCHitTest(const CPoint& pt) {
  // Only do DWM hit-testing when we are using the native frame.
  if (non_client_view_->UseNativeFrame()) {
    LRESULT result;
    if (DwmDefWindowProc(GetHWND(), WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y),
                         &result)) {
      return result;
    }
  }
  return Window::OnNCHitTest(pt);
}

///////////////////////////////////////////////////////////////////////////////
// BrowserFrame, views::CustomFrameWindow overrides:

int BrowserFrame::GetShowState() const {
  return browser_view_->GetShowState();
}

views::NonClientFrameView* BrowserFrame::CreateFrameViewForWindow() {
  if (non_client_view_->UseNativeFrame())
    browser_frame_view_ = new GlassBrowserFrameView(this, browser_view_);
  else
    browser_frame_view_ = new OpaqueBrowserFrameView(this, browser_view_);
  return browser_frame_view_;
}

void BrowserFrame::UpdateFrameAfterFrameChange() {
  Window::UpdateFrameAfterFrameChange();
  UpdateDWMFrame();
}

///////////////////////////////////////////////////////////////////////////////
// BrowserFrame, private:

void BrowserFrame::UpdateDWMFrame() {
  // Nothing to do yet.
  if (!client_view() || !browser_view_->IsBrowserTypeNormal())
    return;

  // In fullscreen mode, we don't extend glass into the client area at all,
  // because the GDI-drawn text in the web content composited over it will
  // become semi-transparent over any glass area.
  MARGINS margins = { 0 };
  if (!browser_view_->IsFullscreen()) {
    margins.cxLeftWidth = kClientEdgeThickness + 1;
    margins.cxRightWidth = kClientEdgeThickness + 1;
    margins.cyTopHeight =
        GetBoundsForTabStrip(browser_view_->tabstrip()).bottom();
    margins.cyBottomHeight = kClientEdgeThickness + 1;
  }
  DwmExtendFrameIntoClientArea(GetHWND(), &margins);
}

<|endoftext|>


<commit_before>
/*sessioncache read generationԼ*/
static inline void __wt_cache_read_gen_incr(WT_SESSION_IMPL* session)
{
	++S2C(session)->cache->read_gen;
}

<commit_msg>增加cache.inl<commit_after>
/*sessioncache read generationԼ*/
static inline void __wt_cache_read_gen_incr(WT_SESSION_IMPL* session)
{
	++S2C(session)->cache->read_gen;
}

static inline void __wt_cache_read_gen(WT_SESSION_IMPL* session)
{
	return (S2C(session)->cache->read_gen);
}

<|endoftext|>


<commit_before>#include "robotboard2interpreter.h"
#include <cstring>
#include <cstdint>

#include <iostream>
#include <cstdio>

RobotBoard2Interpreter::RobotBoard2Interpreter()
    : mpPlaintext()
    , mpHtml()
    , mpJson()
    , mTemperature(0.0f)
    , mCpuCurrent(0.0f)
    , mCpuVoltage(0.0f)
    , mMotorCurrent(0.0f)
    , mMotorVoltage(0.0f)
{
    mTxBuff[0] = 23;
    mTxBuff[1] = 0;

    for(unsigned int i = 2; i < TX_BUFF_SIZE; i++)
    {
        mTxBuff[i] = 0;
    }

    producePlaintext();
    produceHtml();
    produceJson();

    pthread_mutex_init(&mMutex, NULL);

    for(unsigned int i = 0; i < 8; i++)
    {
        setServoPos(i, 90);
    }
}

void RobotBoard2Interpreter::getSettingPacket(uint8_t* outPacketLoc, unsigned int& outPacketLength)
{
    outPacketLength = TX_CONTENT_SIZE;

    enterProtected();
    memcpy(outPacketLoc, mTxBuff, TX_CONTENT_SIZE);
    exitProtected();

    return;
}

// Data: Voltage in mV (2 bytes, signed) | Current in mA (2 bytes, signed) | Temperature in mC (2 bytes, signed)

void RobotBoard2Interpreter::setParamsSerial(const uint8_t *buff, uint16_t buffLength)
{
    /*
    if(!((buffLength == 8) && (buff[1] == 1) && (buff[0] == 8)))
    {
        std::cout << "Bad msg: len " << (unsigned int)buffLength << " - reported " << (unsigned int)buff[0] << ", type " << (unsigned int)buff[1] << std::endl;
        return;
    }
    */

    extractValues(buff, buffLength);
    producePlaintext();
    produceHtml();
    produceJson();
}

void RobotBoard2Interpreter::extractValues(const uint8_t* buffer, uint16_t length)
{
    if((buffer[0] == 1) && length >= 12)
    {
        extractAdcValues(&(buffer[2]), length - 2);
    }
}

void RobotBoard2Interpreter::extractAdcValues(const uint8_t* buffer, uint16_t length)
{
    int16_t tmp;
    float voltage;

    // --MCU Internal temperature--
    tmp = buffer[0] << 8;
    tmp |= buffer[1];

    // The ADC has a 12bit result. But for signed measurements, one bit is the sign.
    // The reference is 3.3V / 1.6
    // 2**12 == 4096, 2**11 == 2048

    // Temperature is an internal mesurement, unsigned, no gain.
    // TODO: find out the temperature/voltage coefficient and zero-point. They're individual for processors.
    mMcuTemperature = (tmp * 1.0f) / 4096.0f * (3.3f / 1.6f);

    // --Temperature sensor--
    tmp = buffer[2] << 8;
    tmp |= buffer[3];

    // Measurement is signed and thus 11bit. Div/2 gain is in effect.
    voltage = (tmp * 1.0f) / 2048.0f * (3.3f * 2.0f / 1.6f);
    // The sensor type in use is MCP9700.
    // Vout = TCoefficient * Ta + V0deg => Ta = (Vout - V0deg) / TCoefficient
    // V0deg is 500mV = 0.5V
    // TCoefficient is 10.0mV/degC = 0.01
    mTemperature = (voltage - 0.5f) / 0.01f;

    // --CPU current--
    tmp = buffer[4] << 8;
    tmp |= buffer[5];

    // Current sense resistor has 2x parallel 0.039 Ohms.
    // Sensor puts out voltage over sense resistor multiplied by 100.
    // Gain setting is Div/2.
    voltage = (tmp * 1.0f) / 2048.0f * (3.3f * 2.0f / 1.6f);
    mCpuCurrent = voltage / (0.039 / 2.0) / 100;

    // --CPU battery voltage--
    tmp = buffer[6] << 8;
    tmp |= buffer[7];

    // Differential, but with no gain, as input is 1/7 of the battery voltage through resistor division.
    voltage = (tmp * 1.0f) / 2048.0f * (3.3f / 1.6f);
    mCpuVoltage = voltage * ((20.0f + 3.3f) / 3.3f);

    // --Motor current--
    tmp = buffer[8] << 8;
    tmp |= buffer[9];

    // The full scale of the current sensors is +/-12A. Zero point is Vcc/2.
    // The input has 0.5x gain. Mode is signed, so full-scale is 2**11.
    voltage = (tmp * 1.0f) / 2048.0f * (3.3f * 2.0f / 1.6f);
    // Deduct 2**11 / 2 == 1024 to make result signed and
    mMotorCurrent = (voltage / (3.3f / 2.0f)) * 12.0f;

    // --Motor voltage--
    tmp = buffer[10] << 8;
    tmp |= buffer[11];

    // Signed, no gain.
    voltage = (tmp * 1.0f) / 2048.0f * (3.3f / 1.6f);
    // The voltage comes through a dividing resistors. Calculate backwards to original.
    mMotorVoltage = voltage * ((20.0f + 4.7f) / 4.7f);
}

void RobotBoard2Interpreter::producePlaintext()
{
    if(mpPlaintext == bufferPlaintext1)
    {
        mpTmp = bufferPlaintext2;
    }
    else
    {
        mpTmp = bufferPlaintext1;
    }

    std::sprintf(mpTmp, "Temperature sensor: %f V \r\n", mTemperature);

    mpPlaintext = mpTmp;
}

void RobotBoard2Interpreter::produceHtml()
{
    if(mpHtml == bufferHtml1)
    {
        mpTmp = bufferHtml2;
    }
    else
    {
        mpTmp = bufferHtml1;
    }

    std::sprintf(mpTmp, "
Temperature sensor: %fV
 CPU Battery: %fV
 CPU Current: %fA
Motor Voltage: %fV
Motor Current: %fA
",
                 mTemperature, mCpuVoltage, mCpuCurrent, mMotorVoltage ,mMotorCurrent);

    mpHtml = mpTmp;
}

void RobotBoard2Interpreter::produceJson()
{
    if(mpJson == bufferJson1)
    {
        mpTmp = bufferJson2;
    }
    else
    {
        mpTmp = bufferJson1;
    }

    std::sprintf(mpTmp, "{ \"temp\": %.1f, \"mv\": %.1f, \"mc\": %.1f, \"cv\": %.1f, \"cc\": %.1f }",
                 mTemperature, mMotorVoltage, mMotorCurrent, mCpuVoltage, mCpuCurrent );

    mpJson = mpTmp;
}

void RobotBoard2Interpreter::enterProtected()
{
    pthread_mutex_lock(&mMutex);
}

void RobotBoard2Interpreter::exitProtected()
{
    pthread_mutex_unlock(&mMutex);
}

const char* RobotBoard2Interpreter::getJson()
{
    return (const char*)mpJson;
}

const char* RobotBoard2Interpreter::getHtml()
{
    return (const char*)mpHtml;
}

const char *RobotBoard2Interpreter::getPlaintext()
{
    return (const char*)mpPlaintext;
}

void RobotBoard2Interpreter::setLed(unsigned int ledNum, bool on)
{
    if(ledNum >= 8)
    {
        return;
    }

    if(on)
    {
        mTxBuff[MsgLengthLen + MsgTypeLen + MotorsTotalLen + ServosTotalLen] |= (1 << ledNum);
    }
    else
    {
        mTxBuff[MsgLengthLen + MsgTypeLen + MotorsTotalLen + ServosTotalLen] &= ~(1 << ledNum);
    }
}

void RobotBoard2Interpreter::setRightMotor(int percent)
{
    if(percent > 100)
    {
        percent = 100;
    }
    else if(percent < -100)
    {
        percent = -100;
    }

    int16_t tmp = percent;
    tmp *= 32;

    enterProtected();

    mTxBuff[MsgLengthLen + MsgTypeLen] = (tmp >> 8) & 0xFF;
    mTxBuff[MsgLengthLen + MsgTypeLen + 1] = tmp & 0xFF;

    exitProtected();
}

void RobotBoard2Interpreter::setLeftMotor(int percent)
{
    if(percent > 100)
    {
        percent = 100;
    }
    else if(percent < -100)
    {
        percent = -100;
    }

    int16_t tmp = percent;
    tmp *= 32;

    enterProtected();

    mTxBuff[MsgLengthLen + MsgTypeLen + MotorLen] = (tmp >> 8) & 0xFF;
    mTxBuff[MsgLengthLen + MsgTypeLen + MotorLen + 1] = tmp & 0xFF;

    exitProtected();
}

void RobotBoard2Interpreter::setServoPos(unsigned int servoNum, uint16_t pos)
{
    if(servoNum >= 8)
    {
        return;
    }

    if(pos > 250)
    {
        pos = 250;
    }

    enterProtected();

    mTxBuff[MsgLengthLen + MsgTypeLen + (2 * MotorLen) + (servoNum * ServoLen)] = (pos >> 8) & 0xFF;
    mTxBuff[MsgLengthLen + MsgTypeLen + (2 * MotorLen) + (servoNum * ServoLen) + 1] = pos & 0xFF;

    exitProtected();
}

void RobotBoard2Interpreter::setCameraPan(int degrees)
{
    if((degrees > 180) || (degrees < 0))
    {
        return;
    }

    float fTmp = degrees;

    fTmp /= 180.0f;
    fTmp *= 250.0f;

    setServoPos(0, fTmp);
}

void RobotBoard2Interpreter::setCameraTilt(int degrees)
{
    if((degrees > 180) || (degrees < 0))
    {
        return;
    }

    float fTmp = degrees;

    fTmp /= 180.0f;
    fTmp *= 250.0f;

    setServoPos(1, fTmp);
}
<commit_msg>Cleaned up the message interpreter in the Daemon.<commit_after>#include "robotboard2interpreter.h"
#include <cstring>
#include <cstdint>

#include <iostream>
#include <cstdio>

RobotBoard2Interpreter::RobotBoard2Interpreter()
    : mpPlaintext()
    , mpHtml()
    , mpJson()
    , mTemperature(0.0f)
    , mCpuCurrent(0.0f)
    , mCpuVoltage(0.0f)
    , mMotorCurrent(0.0f)
    , mMotorVoltage(0.0f)
{
    mTxBuff[0] = 23;
    mTxBuff[1] = 0;

    for(unsigned int i = 2; i < TX_BUFF_SIZE; i++)
    {
        mTxBuff[i] = 0;
    }

    producePlaintext();
    produceHtml();
    produceJson();

    pthread_mutex_init(&mMutex, NULL);

    for(unsigned int i = 0; i < 8; i++)
    {
        setServoPos(i, 90);
    }
}

void RobotBoard2Interpreter::getSettingPacket(uint8_t* outPacketLoc, unsigned int& outPacketLength)
{
    outPacketLength = TX_CONTENT_SIZE;

    enterProtected();
    memcpy(outPacketLoc, mTxBuff, TX_CONTENT_SIZE);
    exitProtected();

    return;
}

// Data: Voltage in mV (2 bytes, signed) | Current in mA (2 bytes, signed) | Temperature in mC (2 bytes, signed)

void RobotBoard2Interpreter::setParamsSerial(const uint8_t *buff, uint16_t buffLength)
{
    /*
    if(!((buffLength == 8) && (buff[1] == 1) && (buff[0] == 8)))
    {
        std::cout << "Bad msg: len " << (unsigned int)buffLength << " - reported " << (unsigned int)buff[0] << ", type " << (unsigned int)buff[1] << std::endl;
        return;
    }
    */

    extractValues(buff, buffLength);
    producePlaintext();
    produceHtml();
    produceJson();
}

void RobotBoard2Interpreter::extractValues(const uint8_t* buffer, uint16_t length)
{
    if((buffer[0] == 1) && length >= 12)
    {
        extractAdcValues(&(buffer[2]), length - 2);
    }
}

void RobotBoard2Interpreter::extractAdcValues(const uint8_t* buffer, uint16_t length)
{
    int16_t iTmp;
    uint16_t tmp;

    // --PCB temperature--
    iTmp = buffer[2] << 8;
    iTmp |= buffer[3];

    mTemperature = (iTmp * 1.0f) / 10.0f;

    // --CPU current--
    tmp = buffer[4] << 8;
    tmp |= buffer[5];

    mCpuCurrent = (tmp * 1.0f) / 1000.0f;

    // --CPU battery voltage--
    tmp = buffer[6] << 8;
    tmp |= buffer[7];

    mCpuVoltage = (tmp * 1.0f) / 1000.0f;

    // --Motor current--
    tmp = buffer[8] << 8;
    tmp |= buffer[9];

    mMotorCurrent = (tmp * 1.0f) / 1000.0f;

    // --Motor voltage--
    tmp = buffer[10] << 8;
    tmp |= buffer[11];

    mMotorVoltage = (tmp * 1.0f) / 1000.0f;
}

void RobotBoard2Interpreter::producePlaintext()
{
    if(mpPlaintext == bufferPlaintext1)
    {
        mpTmp = bufferPlaintext2;
    }
    else
    {
        mpTmp = bufferPlaintext1;
    }

    std::sprintf(mpTmp, "Temperature sensor: %f V \r\n", mTemperature);

    mpPlaintext = mpTmp;
}

void RobotBoard2Interpreter::produceHtml()
{
    if(mpHtml == bufferHtml1)
    {
        mpTmp = bufferHtml2;
    }
    else
    {
        mpTmp = bufferHtml1;
    }

    std::sprintf(mpTmp, "
Temperature sensor: %fV
 CPU Battery: %fV
 CPU Current: %fA
Motor Voltage: %fV
Motor Current: %fA
",
                 mTemperature, mCpuVoltage, mCpuCurrent, mMotorVoltage ,mMotorCurrent);

    mpHtml = mpTmp;
}

void RobotBoard2Interpreter::produceJson()
{
    if(mpJson == bufferJson1)
    {
        mpTmp = bufferJson2;
    }
    else
    {
        mpTmp = bufferJson1;
    }

    std::sprintf(mpTmp, "{ \"temp\": %.1f, \"mv\": %.1f, \"mc\": %.1f, \"cv\": %.1f, \"cc\": %.1f }",
                 mTemperature, mMotorVoltage, mMotorCurrent, mCpuVoltage, mCpuCurrent );

    mpJson = mpTmp;
}

void RobotBoard2Interpreter::enterProtected()
{
    pthread_mutex_lock(&mMutex);
}

void RobotBoard2Interpreter::exitProtected()
{
    pthread_mutex_unlock(&mMutex);
}

const char* RobotBoard2Interpreter::getJson()
{
    return (const char*)mpJson;
}

const char* RobotBoard2Interpreter::getHtml()
{
    return (const char*)mpHtml;
}

const char *RobotBoard2Interpreter::getPlaintext()
{
    return (const char*)mpPlaintext;
}

void RobotBoard2Interpreter::setLed(unsigned int ledNum, bool on)
{
    if(ledNum >= 8)
    {
        return;
    }

    if(on)
    {
        mTxBuff[MsgLengthLen + MsgTypeLen + MotorsTotalLen + ServosTotalLen] |= (1 << ledNum);
    }
    else
    {
        mTxBuff[MsgLengthLen + MsgTypeLen + MotorsTotalLen + ServosTotalLen] &= ~(1 << ledNum);
    }
}

void RobotBoard2Interpreter::setRightMotor(int percent)
{
    if(percent > 100)
    {
        percent = 100;
    }
    else if(percent < -100)
    {
        percent = -100;
    }

    int16_t tmp = percent;
    tmp *= 32;

    enterProtected();

    mTxBuff[MsgLengthLen + MsgTypeLen] = (tmp >> 8) & 0xFF;
    mTxBuff[MsgLengthLen + MsgTypeLen + 1] = tmp & 0xFF;

    exitProtected();
}

void RobotBoard2Interpreter::setLeftMotor(int percent)
{
    if(percent > 100)
    {
        percent = 100;
    }
    else if(percent < -100)
    {
        percent = -100;
    }

    int16_t tmp = percent;
    tmp *= 32;

    enterProtected();

    mTxBuff[MsgLengthLen + MsgTypeLen + MotorLen] = (tmp >> 8) & 0xFF;
    mTxBuff[MsgLengthLen + MsgTypeLen + MotorLen + 1] = tmp & 0xFF;

    exitProtected();
}

void RobotBoard2Interpreter::setServoPos(unsigned int servoNum, uint16_t pos)
{
    if(servoNum >= 8)
    {
        return;
    }

    if(pos > 250)
    {
        pos = 250;
    }

    enterProtected();

    mTxBuff[MsgLengthLen + MsgTypeLen + (2 * MotorLen) + (servoNum * ServoLen)] = (pos >> 8) & 0xFF;
    mTxBuff[MsgLengthLen + MsgTypeLen + (2 * MotorLen) + (servoNum * ServoLen) + 1] = pos & 0xFF;

    exitProtected();
}

void RobotBoard2Interpreter::setCameraPan(int degrees)
{
    if((degrees > 180) || (degrees < 0))
    {
        return;
    }

    float fTmp = degrees;

    fTmp /= 180.0f;
    fTmp *= 250.0f;

    setServoPos(0, fTmp);
}

void RobotBoard2Interpreter::setCameraTilt(int degrees)
{
    if((degrees > 180) || (degrees < 0))
    {
        return;
    }

    float fTmp = degrees;

    fTmp /= 180.0f;
    fTmp *= 250.0f;

    setServoPos(1, fTmp);
}
<|endoftext|>


<commit_before>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include <fstream>
#include <exception>
#include <string>
#include <limits>
#include <cctype>
#include <CImg.h>

#include <ArgumentList.hpp>
#include <ColorMap.hpp>
#include <utils.hpp>

int main(int argc, char * argv[]) {
  unsigned int nrDMs = 0;
  unsigned int nrPeriods = 0;
  float minSNR = std::numeric_limits< float >::max();
  float maxSNR = std::numeric_limits< float >::min();
  float snrSpaceDim = 0.0f;
  float * snrSpace = 0;
  std::string outFilename;
  std::ifstream searchFile;

  isa::utils::ArgumentList args(argc, argv);
  try {
    outFilename = args.getSwitchArgument< std::string >("-output");
    nrDMs = args.getSwitchArgument< unsigned int >("-dms");
    nrPeriods = args.getSwitchArgument< unsigned int >("-periods");
  } catch ( isa::utils::EmptyCommandLine & err ) {
    std::cerr << args.getName() << " -output ... -dms ... -periods ... input" << std::endl;
    return 1;
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  snrSpace = new float [nrDMs * nrPeriods];

  try {
    while ( true ) {
      searchFile.open(args.getFirst< std::string >());

      while ( ! searchFile.eof() ) {
        std::string temp;
        unsigned int splitPoint = 0;
        unsigned int DM = 0;
        unsigned int period = 0;
        float snr = 0.0f;

        std::getline(searchFile, temp);
        if ( ! std::isdigit(temp[0]) ) {
          continue;
        }
        splitPoint = temp.find(" ");
        period = isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint));
        temp = temp.substr(splitPoint + 1);
        splitPoint = temp.find(" ");
        DM = isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint));
        temp = temp.substr(splitPoint + 1);
        splitPoint = temp.find(" ");
        snr = isa::utils::castToType< std::string, float >(temp);

        if ( snr > maxSNR ) {
          maxSNR = snr;
        }
        if ( snr < minSNR ) {
          minSNR = snr;
        }

        snrSpace[(period * nrDMs) + DM] = snr;
      }
      searchFile.close();
    }
  } catch ( isa::utils::EmptyCommandLine & err ) {
    snrSpaceDim = maxSNR - minSNR;
  }

  cimg_library::CImg< unsigned char > searchImage(nrDMs, nrPeriods, 1, 3);
  AstroData::Color *colorMap = AstroData::getColorMap();
  for ( unsigned int period = 0; period < nrPeriods; period++ ) {
    for ( unsigned int DM = 0; DM < nrDMs; DM++ ) {
      float snr = snrSpace[(period * nrDMs) + DM];
      searchImage((nrDMs - 1) - DM, period, 0, 0) = (colorMap[static_cast< unsigned int >(((snr - minSNR) * 256.0f) / snrSpaceDim)]).getR();
      searchImage((nrDMs - 1) - DM, period, 0, 1) = (colorMap[static_cast< unsigned int >(((snr - minSNR) * 256.0f) / snrSpaceDim)]).getG();
      searchImage((nrDMs - 1 ) - DM, period, 0, 2) = (colorMap[static_cast< unsigned int >(((snr - minSNR) * 256.0f) / snrSpaceDim)]).getB();
    }
  }
  searchImage.save(outFilename.c_str());

  delete [] snrSpace;
  return 0;
}

<commit_msg>Fixed the image of the search space to have axes as you would expect them to be.<commit_after>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include <fstream>
#include <exception>
#include <string>
#include <limits>
#include <cctype>
#include <CImg.h>

#include <ArgumentList.hpp>
#include <ColorMap.hpp>
#include <utils.hpp>

int main(int argc, char * argv[]) {
  unsigned int nrDMs = 0;
  unsigned int nrPeriods = 0;
  float minSNR = std::numeric_limits< float >::max();
  float maxSNR = std::numeric_limits< float >::min();
  float snrSpaceDim = 0.0f;
  float * snrSpace = 0;
  std::string outFilename;
  std::ifstream searchFile;

  isa::utils::ArgumentList args(argc, argv);
  try {
    outFilename = args.getSwitchArgument< std::string >("-output");
    nrDMs = args.getSwitchArgument< unsigned int >("-dms");
    nrPeriods = args.getSwitchArgument< unsigned int >("-periods");
  } catch ( isa::utils::EmptyCommandLine & err ) {
    std::cerr << args.getName() << " -output ... -dms ... -periods ... input" << std::endl;
    return 1;
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  snrSpace = new float [nrDMs * nrPeriods];

  try {
    while ( true ) {
      searchFile.open(args.getFirst< std::string >());

      while ( ! searchFile.eof() ) {
        std::string temp;
        unsigned int splitPoint = 0;
        unsigned int DM = 0;
        unsigned int period = 0;
        float snr = 0.0f;

        std::getline(searchFile, temp);
        if ( ! std::isdigit(temp[0]) ) {
          continue;
        }
        splitPoint = temp.find(" ");
        period = isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint));
        temp = temp.substr(splitPoint + 1);
        splitPoint = temp.find(" ");
        DM = isa::utils::castToType< std::string, unsigned int >(temp.substr(0, splitPoint));
        temp = temp.substr(splitPoint + 1);
        splitPoint = temp.find(" ");
        snr = isa::utils::castToType< std::string, float >(temp);

        if ( snr > maxSNR ) {
          maxSNR = snr;
        }
        if ( snr < minSNR ) {
          minSNR = snr;
        }

        snrSpace[(period * nrDMs) + DM] = snr;
      }
      searchFile.close();
    }
  } catch ( isa::utils::EmptyCommandLine & err ) {
    snrSpaceDim = maxSNR - minSNR;
  }

  cimg_library::CImg< unsigned char > searchImage(nrDMs, nrPeriods, 1, 3);
  AstroData::Color *colorMap = AstroData::getColorMap();
  for ( unsigned int period = 0; period < nrPeriods; period++ ) {
    for ( unsigned int DM = 0; DM < nrDMs; DM++ ) {
      float snr = snrSpace[(period * nrDMs) + DM];
      searchImage(DM, (nrPeriods - 1) - period, 0, 0) = (colorMap[static_cast< unsigned int >(((snr - minSNR) * 256.0f) / snrSpaceDim)]).getR();
      searchImage(DM, (nrPeriods - 1) - period, 0, 1) = (colorMap[static_cast< unsigned int >(((snr - minSNR) * 256.0f) / snrSpaceDim)]).getG();
      searchImage((nrDMs - 1 ) - DM, (nrPeriods - 1) - period, 0, 2) = (colorMap[static_cast< unsigned int >(((snr - minSNR) * 256.0f) / snrSpaceDim)]).getB();
    }
  }
  searchImage.save(outFilename.c_str());

  delete [] snrSpace;
  return 0;
}

<|endoftext|>


<commit_before>/* Copyright 2014 Jonas Platte
 *
 * This file is part of Cyvasse Online.
 *
 * Cyvasse Online is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * Cyvasse Online 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _CYVMATH_HEXAGON_HPP_
#define _CYVMATH_HEXAGON_HPP_

#include <functional>
#include <set>
#include <string>
#include <stdexcept>
#include <cmath>

namespace cyvmath
{
	/* This should rather be a namespace, but namespaces cannot have template parameters.
	   hexagon<6>::Coordinate is way better understandable than hexagon::Coordinate<6>
	   so this is implemented as a template class with a deleted constructor.
	   The template parameter l stands for the edge length of the hexagon.
	 */
	template <int l>
	class hexagon
	{
		/* The smallest possible hexagon has 7 tiles and an edge lenth of 2
		   The largest possible hexagon in which the highest x and y can be represented
		   using a signed 8 bit integer has an edge length of 64 (=> width and height 127)
		 */
		static_assert(l >= 2,  "The minimum size of the hexagon edge length is 2.");
		static_assert(l <= 64, "The maximum size of the hexagon edge length is 64.");

		private:
			hexagon() = delete;

		public:
			/// A coordinate on the hexboard (see mockup/hexboard-coordinates-internal.svg)
			class Coordinate
			{
				private:
					int8_t _x;
					int8_t _y;

					int8_t z()
					{
						return -(_x + _y);
					}

					void throwInvalid()
					{
						throw std::invalid_argument("Coordinate not valid: "
						                            "{" + std::to_string(_x) +
						                            ", " + std::to_string(_y) + "}");
					}

				public:
					Coordinate(int8_t x, int8_t y)
						: _x(x)
						, _y(y)
					{
						if(!isValid())
							throwInvalid();
					}

					int8_t x()
					{
						return _x;
					}

					int8_t y()
					{
						return _y;
					}

					bool isValid()
					{
						return (_x + _y) >= (l - 1) &&
						       (_x + _y) <= (l - 1) * 3;
					}

					operator bool()
					{
						return isValid();
					}

					/** Get the distance to another coordinate in form of the amount
					    of single moves to adjacent tiles required to move there
					 */
					int8_t getDistance(Coordinate other)
					{
						// I have no idea how or why this works, but it does.
						// Taken from http://keekerdc.com/2011/03/hexagon-grids-coordinate-systems-and-distance-calculations/
						return *(std::set<int>({abs(_x - other._x), abs(_y - other._y), abs(z() - other.z())}).rbegin());
					}

					/// Check if the given coordinate is reachable in one orthogonal move
					bool isOrthogonal(Coordinate other)
					{
						return _x == other._x || _y == other._y || z() == other.z();
					}

					/** Like getDistance(), but return -1 if the given coordinate
					    is not reachable in one orthogonal move

					    An orthogonal move is a straight move in one of the six
					    directions of the neighboring hex-tiles.
					 */
					int8_t getDistanceOrthogonal(Coordinate other)
					{
						if(!isOrthogonal(other))
							return -1;

						return getDistance(other);
					}

					/// Check if the given coordinate is reachable in one diagonal move
					bool isDiagonal(Coordinate other)
					{
						int8_t dX = abs(_x - other._x);
						int8_t dY = abs(_y - other._y);
						int8_t dZ = abs(z() - other.z());

						return (dX == dY && dX == dZ / 2) ||
						       (dX == dZ && dX == dY / 2) ||
						       (dY == dZ && dY == dX / 2);
					}

					/** Get the diagonal distance to a coordinate, or -1 if
					    the coordinate isn't reachable in one diagonal move

					    A diagonal move is a straight move in one of the six
					    directions of the lines between the neighboring hex-tiles.
					 */
					int8_t getDistanceDiagonal(Coordinate other)
					{
						if(!isDiagonal(other))
							return -1;

						return getDistance(other) / 2;
					}

					/** Get the distance to another coordinate with the same distance to
					    the center Coordinate along the line of these coordinates, or -1
					    if the coordinate isn't reachable while only moving on that line.

					    All possible movement targets here are along a hexagonal line.
					    The direct distance from this coordinate to another one on that
					    line may be different than the distance along the line.
					 */
					// There certainly is no other ruleset than MikeL's that uses this
					// but there probably is no better place to put this code either.
					int8_t getDistanceHexagonalLine(Coordinate other, Coordinate center)
					{
						// Check if the given coordinate has the same distance to center as this
						if(getDistance(center) != other.getDistance(center))
							return -1;

						// TODO
					}

					/// Check if the given coordinate is a direct neighbor
					bool isAdjacent(Coordinate other)
					{
						return getDistance() == 1;
					}

					void set(int8_t x, int8_t y)
					{
						_x = x;
						_y = y;

						if(!isValid())
							throwInvalid();
					}

					Coordinate& operator=(Coordinate other)
					{
						set(other._x, other._y);
						return *this;
					}

					/// Create a Coordinate object from a coordinate in the public notation
					/// (see mockup/hexboard-coordinates-public.svg)
					static Coordinate fromStr(const std::string& str)
					{
						// This function will currently fail on hexagons with l > 13 because there
						// would be multiple letters for the y coordinate in the public notation.
						// TODO: Decide on whether to set a maximum l of 13 or to alter this function

						if(str.length() < 2)
							throw std::invalid_argument("Coordinate not valid");

						/* x: When using char's for calculations, their ASCII values are used,
						      and as the uppercase letters are consecutive in the ASCII table,
						      this will result in 0 for 'A', 1 for 'B' and so on.
						      We don't accept lowercase letters.
						   y: Public coordinate notation starts with 1, we start with 0
						 */
						return {str.at(0) - 'A', std::stoi(str.substr(1)) - 1};
					}
			};

			struct CoordinateHash
			{
				size_t operator()(const Coordinate& c) const
				{
					return std::hash<int>() ((c.x() << 8) | c.y());
				}
			};
	};
}

#endif // _CYVMATH_HEXAGON_HPP_
<commit_msg>Added hexagon::getAllCoordinates()<commit_after>/* Copyright 2014 Jonas Platte
 *
 * This file is part of Cyvasse Online.
 *
 * Cyvasse Online is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * Cyvasse Online 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _CYVMATH_HEXAGON_HPP_
#define _CYVMATH_HEXAGON_HPP_

#include <functional>
#include <set>
#include <string>
#include <stdexcept>
#include <vector>
#include <cmath>

namespace cyvmath
{
	/* This should rather be a namespace, but namespaces cannot have template parameters.
	   hexagon<6>::Coordinate is way better understandable than hexagon::Coordinate<6>
	   so this is implemented as a template class with a deleted constructor.
	   The template parameter l stands for the edge length of the hexagon.
	 */
	template <int l>
	class hexagon
	{
		/* The smallest possible hexagon has 7 tiles and an edge lenth of 2
		   The largest possible hexagon in which the highest x and y can be represented
		   using a signed 8 bit integer has an edge length of 64 (=> width and height 127)
		 */
		static_assert(l >= 2,  "The minimum size of the hexagon edge length is 2.");
		static_assert(l <= 64, "The maximum size of the hexagon edge length is 64.");

		private:
			hexagon() = delete;

		public:
			/// A coordinate on the hexboard (see mockup/hexboard-coordinates-internal.svg)
			class Coordinate
			{
				private:
					int8_t _x;
					int8_t _y;

					int8_t z()
					{
						return -(_x + _y);
					}

					void throwInvalid()
					{
						throw std::invalid_argument("Coordinate not valid: "
						                            "{" + std::to_string(_x) +
						                            ", " + std::to_string(_y) + "}");
					}

				public:
					Coordinate(int8_t x, int8_t y)
						: _x(x)
						, _y(y)
					{
						if(!isValid())
							throwInvalid();
					}

					int8_t x() const
					{
						return _x;
					}

					int8_t y() const
					{
						return _y;
					}

					bool isValid() const
					{
						return (_x + _y) >= (l - 1) &&
						       (_x + _y) <= (l - 1) * 3;
					}

					operator bool() const
					{
						return isValid();
					}

					/** Get the distance to another coordinate in form of the amount
					    of single moves to adjacent tiles required to move there
					 */
					int8_t getDistance(Coordinate other) const
					{
						// I have no idea how or why this works, but it does.
						// Taken from http://keekerdc.com/2011/03/hexagon-grids-coordinate-systems-and-distance-calculations/
						return *(std::set<int>({abs(_x - other._x), abs(_y - other._y), abs(z() - other.z())}).rbegin());
					}

					/// Check if the given coordinate is reachable in one orthogonal move
					bool isOrthogonal(Coordinate other) const
					{
						return _x == other._x || _y == other._y || z() == other.z();
					}

					/** Like getDistance(), but return -1 if the given coordinate
					    is not reachable in one orthogonal move

					    An orthogonal move is a straight move in one of the six
					    directions of the neighboring hex-tiles.
					 */
					int8_t getDistanceOrthogonal(Coordinate other) const
					{
						if(!isOrthogonal(other))
							return -1;

						return getDistance(other);
					}

					/// Check if the given coordinate is reachable in one diagonal move
					bool isDiagonal(Coordinate other) const
					{
						int8_t dX = abs(_x - other._x);
						int8_t dY = abs(_y - other._y);
						int8_t dZ = abs(z() - other.z());

						return (dX == dY && dX == dZ / 2) ||
						       (dX == dZ && dX == dY / 2) ||
						       (dY == dZ && dY == dX / 2);
					}

					/** Get the diagonal distance to a coordinate, or -1 if
					    the coordinate isn't reachable in one diagonal move

					    A diagonal move is a straight move in one of the six
					    directions of the lines between the neighboring hex-tiles.
					 */
					int8_t getDistanceDiagonal(Coordinate other) const
					{
						if(!isDiagonal(other))
							return -1;

						return getDistance(other) / 2;
					}

					/** Get the distance to another coordinate with the same distance to
					    the center Coordinate along the line of these coordinates, or -1
					    if the coordinate isn't reachable while only moving on that line.

					    All possible movement targets here are along a hexagonal line.
					    The direct distance from this coordinate to another one on that
					    line may be different than the distance along the line.
					 */
					// There certainly is no other ruleset than MikeL's that uses this
					// but there probably is no better place to put this code either.
					int8_t getDistanceHexagonalLine(Coordinate other, Coordinate center) const
					{
						// Check if the given coordinate has the same distance to center as this
						if(getDistance(center) != other.getDistance(center))
							return -1;

						// TODO
					}

					/// Check if the given coordinate is a direct neighbor
					bool isAdjacent(Coordinate other) const
					{
						return getDistance() == 1;
					}

					void set(int8_t x, int8_t y)
					{
						_x = x;
						_y = y;

						if(!isValid())
							throwInvalid();
					}

					Coordinate& operator=(Coordinate other)
					{
						set(other._x, other._y);
						return *this;
					}

					/// Create a Coordinate object from a coordinate in the public notation
					/// (see mockup/hexboard-coordinates-public.svg)
					static Coordinate fromStr(const std::string& str)
					{
						// This function will currently fail on hexagons with l > 13 because there
						// would be multiple letters for the y coordinate in the public notation.
						// TODO: Decide on whether to set a maximum l of 13 or to alter this function

						if(str.length() < 2)
							throw std::invalid_argument("Coordinate not valid");

						/* x: When using char's for calculations, their ASCII values are used,
						      and as the uppercase letters are consecutive in the ASCII table,
						      this will result in 0 for 'A', 1 for 'B' and so on.
						      We don't accept lowercase letters.
						   y: Public coordinate notation starts with 1, we start with 0
						 */
						return {str.at(0) - 'A', std::stoi(str.substr(1)) - 1};
					}
			};

			/// Get a container with all possible coordinates in this hexagon
			static std::vector<Coordinate> getAllCoordinates()
			{
				static std::vector<Coordinate> vec;

				if(vec.empty())
				{
					// TODO: Should we instead iterate x and y over the full range
					// of coordinates (0 to [excl] l - 1) and catch errors thrown
					// by the Coordinate constructor? (isValid() is called anyway)
					for(int x = 0; x < 2 * l - 1; x++)
					{
						int y = l - 1 - x;
						if(y < 0) y = 0;

						for(; y < 2 * l - 1 && x + y < (l - 1) * 3; y++)
						{
							vec.emplace_back(x, y);
						}
					}
				}

				return vec;
			}

			struct CoordinateHash
			{
				size_t operator()(const Coordinate& c) const
				{
					return std::hash<int>() ((c.x() << 8) | c.y());
				}
			};
	};
}

#endif // _CYVMATH_HEXAGON_HPP_
<|endoftext|>