<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mc/perf_reg.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file perf_reg.C
/// @brief Subroutines to manipulate the memory controller performance registers
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>

#include <p9_mc_scom_addresses.H>
#include <p9_mc_scom_addresses_fld.H>

#include <lib/mss_attribute_accessors.H>

#include <lib/mc/mc.H>
#include <lib/utils/scom.H>
#include <lib/dimm/kind.H>
#include <lib/utils/find.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCS;
using fapi2::TARGET_TYPE_DIMM;

namespace mss
{

namespace mc
{

///
/// @brief Perform initializations of the MC performance registers
/// @note Some of these bits are taken care of in the scom initfiles
/// @param[in] i_target the target which has the MCA to map
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode setup_perf2_register(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
{
    fapi2::buffer<uint64_t> l_data;

    // Get the values we need to put in the register
    uint64_t l_value;
    FAPI_TRY( calculate_perf2(i_target, l_value) );

    // Setup the registers
    FAPI_TRY( mss::getScom(i_target, MCS_0_PORT02_MCPERF2, l_data) );

    // Per S. Powell 7/16, setup these registers but don't enable the function yet. So enable bits are
    // intentionally not set
    l_data.insertFromRight<MCS_PORT02_MCPERF2_REFRESH_BLOCK_CONFIG,
                           MCS_PORT02_MCPERF2_REFRESH_BLOCK_CONFIG_LEN>(l_value);

    FAPI_TRY( mss::putScom(i_target, MCS_0_PORT02_MCPERF2, l_data) );

fapi_try_exit:
    return fapi2::FAPI2_RC_SUCCESS;
}

///
/// @brief Calculate the value of the MC perf2 register.
/// @param[in] i_target the target which has the MCA to map
/// @param[out] o_value the perf2 value for the MCA
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode calculate_perf2(const fapi2::Target<TARGET_TYPE_MCA>& i_target, uint64_t& o_value)
{
    //
    // From Senor Powell 7/16
    // if (slots=1, masters=1)
    //   MCPERF2_Refresh_Block_Config=0b000
    // if (slots=1, masters=2)
    //   MCPERF2_Refresh_Block_Config=0b001
    // if (slots=1, masters=4)
    //  MCPERF2_Refresh_Block_Config=0b100
    // if (slots=2, masters=1)
    //  MCPERF2_Refresh_Block_Config=0b010
    // if (slots=2, masters=2)
    //  MCPERF2_Refresh_Block_Config=0b011
    // if (slots=2, masters=4)
    //  MCPERF2_Refresh_Block_Config=0b100
    //
    // if slot0 is 2 masters and slot1 is 1 master, just choose the 2 slot, 2 masters setting.
    // (i.e., choose the max(mranks_dimm1, mranks_dimm2)

    constexpr uint64_t l_refresh_values[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM] =
    {
        {0b000, 0b001, 0, 0b100}, // Skip the ol' 3 rank DIMM
        {0b010, 0b011, 0, 0b100}
    };

    FAPI_INF("Calculating perf2 register for MCA%d (%d)", mss::pos(i_target), mss::index(i_target));

    // Find the DIMM on this port with the most master ranks.
    // That's how we know which element in the table to use.
    // uint8_t so I can use it to read from an attribute directly

    uint8_t l_mrank_index = 0;
    uint8_t l_master_ranks_zero = 0;
    uint8_t l_master_ranks_one = 0;

    fapi2::buffer<uint64_t> l_data;

    const auto l_dimm = mss::find_targets<TARGET_TYPE_DIMM>(i_target);
    const auto l_slot_index = l_dimm.size() - 1;

    switch(l_dimm.size())
    {
        // No DIMM, nothing to do
        case 0:
            return fapi2::FAPI2_RC_SUCCESS;
            break;

        // One DIMM, we've got the slots of fun
        case 1:
            FAPI_TRY( mss::eff_num_master_ranks_per_dimm(l_dimm[0], l_mrank_index) );
            --l_mrank_index;
            FAPI_INF("1 DIMM mranks: D0[%d] index %d", l_mrank_index + 1, l_mrank_index);
            break;

        // Two DIMM, find the max of the master ranks
        case 2:
            {
                FAPI_TRY( mss::eff_num_master_ranks_per_dimm(l_dimm[0], l_master_ranks_zero) );
                FAPI_TRY( mss::eff_num_master_ranks_per_dimm(l_dimm[1], l_master_ranks_one) );

                l_mrank_index = std::max(l_master_ranks_zero, l_master_ranks_one) - 1;
                FAPI_INF("2 DIMM mranks: D0[%d] D1[%d] index %d", l_master_ranks_zero, l_master_ranks_one, l_mrank_index);
            }
            break;

        default:
            // We have a bug - no way to get more than 2 DIMM in a dual-drop system
            FAPI_ERR("seeing %d DIMM on %s", l_dimm.size(), mss::c_str(i_target));
            fapi2::Assert(false);
            break;
    };

    FAPI_INF("Refresh Block Config: %u ([%d][%d] populated slots: %d, max mranks: %d)",
             l_refresh_values[l_slot_index][l_mrank_index],
             l_slot_index, l_mrank_index,
             l_slot_index + 1, l_mrank_index + 1);

    o_value = l_refresh_values[l_slot_index][l_mrank_index];

fapi_try_exit:
    return fapi2::current_err;
}

} // namespace

} // namespace
<commit_msg>Move scom API to share among controllers<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mc/perf_reg.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file perf_reg.C
/// @brief Subroutines to manipulate the memory controller performance registers
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>

#include <p9_mc_scom_addresses.H>
#include <p9_mc_scom_addresses_fld.H>

#include <lib/mss_attribute_accessors.H>

#include <lib/mc/mc.H>
#include <generic/memory/lib/utils/scom.H>
#include <lib/dimm/kind.H>
#include <lib/utils/find.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCS;
using fapi2::TARGET_TYPE_DIMM;

namespace mss
{

namespace mc
{

///
/// @brief Perform initializations of the MC performance registers
/// @note Some of these bits are taken care of in the scom initfiles
/// @param[in] i_target the target which has the MCA to map
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode setup_perf2_register(const fapi2::Target<TARGET_TYPE_MCA>& i_target)
{
    fapi2::buffer<uint64_t> l_data;

    // Get the values we need to put in the register
    uint64_t l_value;
    FAPI_TRY( calculate_perf2(i_target, l_value) );

    // Setup the registers
    FAPI_TRY( mss::getScom(i_target, MCS_0_PORT02_MCPERF2, l_data) );

    // Per S. Powell 7/16, setup these registers but don't enable the function yet. So enable bits are
    // intentionally not set
    l_data.insertFromRight<MCS_PORT02_MCPERF2_REFRESH_BLOCK_CONFIG,
                           MCS_PORT02_MCPERF2_REFRESH_BLOCK_CONFIG_LEN>(l_value);

    FAPI_TRY( mss::putScom(i_target, MCS_0_PORT02_MCPERF2, l_data) );

fapi_try_exit:
    return fapi2::FAPI2_RC_SUCCESS;
}

///
/// @brief Calculate the value of the MC perf2 register.
/// @param[in] i_target the target which has the MCA to map
/// @param[out] o_value the perf2 value for the MCA
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode calculate_perf2(const fapi2::Target<TARGET_TYPE_MCA>& i_target, uint64_t& o_value)
{
    //
    // From Senor Powell 7/16
    // if (slots=1, masters=1)
    //   MCPERF2_Refresh_Block_Config=0b000
    // if (slots=1, masters=2)
    //   MCPERF2_Refresh_Block_Config=0b001
    // if (slots=1, masters=4)
    //  MCPERF2_Refresh_Block_Config=0b100
    // if (slots=2, masters=1)
    //  MCPERF2_Refresh_Block_Config=0b010
    // if (slots=2, masters=2)
    //  MCPERF2_Refresh_Block_Config=0b011
    // if (slots=2, masters=4)
    //  MCPERF2_Refresh_Block_Config=0b100
    //
    // if slot0 is 2 masters and slot1 is 1 master, just choose the 2 slot, 2 masters setting.
    // (i.e., choose the max(mranks_dimm1, mranks_dimm2)

    constexpr uint64_t l_refresh_values[MAX_DIMM_PER_PORT][MAX_RANK_PER_DIMM] =
    {
        {0b000, 0b001, 0, 0b100}, // Skip the ol' 3 rank DIMM
        {0b010, 0b011, 0, 0b100}
    };

    FAPI_INF("Calculating perf2 register for MCA%d (%d)", mss::pos(i_target), mss::index(i_target));

    // Find the DIMM on this port with the most master ranks.
    // That's how we know which element in the table to use.
    // uint8_t so I can use it to read from an attribute directly

    uint8_t l_mrank_index = 0;
    uint8_t l_master_ranks_zero = 0;
    uint8_t l_master_ranks_one = 0;

    fapi2::buffer<uint64_t> l_data;

    const auto l_dimm = mss::find_targets<TARGET_TYPE_DIMM>(i_target);
    const auto l_slot_index = l_dimm.size() - 1;

    switch(l_dimm.size())
    {
        // No DIMM, nothing to do
        case 0:
            return fapi2::FAPI2_RC_SUCCESS;
            break;

        // One DIMM, we've got the slots of fun
        case 1:
            FAPI_TRY( mss::eff_num_master_ranks_per_dimm(l_dimm[0], l_mrank_index) );
            --l_mrank_index;
            FAPI_INF("1 DIMM mranks: D0[%d] index %d", l_mrank_index + 1, l_mrank_index);
            break;

        // Two DIMM, find the max of the master ranks
        case 2:
            {
                FAPI_TRY( mss::eff_num_master_ranks_per_dimm(l_dimm[0], l_master_ranks_zero) );
                FAPI_TRY( mss::eff_num_master_ranks_per_dimm(l_dimm[1], l_master_ranks_one) );

                l_mrank_index = std::max(l_master_ranks_zero, l_master_ranks_one) - 1;
                FAPI_INF("2 DIMM mranks: D0[%d] D1[%d] index %d", l_master_ranks_zero, l_master_ranks_one, l_mrank_index);
            }
            break;

        default:
            // We have a bug - no way to get more than 2 DIMM in a dual-drop system
            FAPI_ERR("seeing %d DIMM on %s", l_dimm.size(), mss::c_str(i_target));
            fapi2::Assert(false);
            break;
    };

    FAPI_INF("Refresh Block Config: %u ([%d][%d] populated slots: %d, max mranks: %d)",
             l_refresh_values[l_slot_index][l_mrank_index],
             l_slot_index, l_mrank_index,
             l_slot_index + 1, l_mrank_index + 1);

    o_value = l_refresh_values[l_slot_index][l_mrank_index];

fapi_try_exit:
    return fapi2::current_err;
}

} // namespace

} // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2016, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include <string>
#include <map>

#include <gflags/gflags.h>
#include <leveldb/db.h>

#include <common/string_util.h>
#include <common/logging.h>

#include "proto/block.pb.h"

#include "utils/meta_converter.h"

namespace baidu {
namespace bfs {

const int CHUNKSERVER_META_VERSION = 1;

const int EMPTY_META = -1;

void CheckChunkserverMeta(const std::vector<std::string>& store_path_list) {
    std::map<std::string, leveldb::DB*> meta_dbs;
    int meta_version = EMPTY_META;
    for (size_t i = 0; i < store_path_list.size(); ++i) {
        const std::string& path = store_path_list[i];
        leveldb::Options options;
        options.create_if_missing = true;
        leveldb::DB* metadb;
        leveldb::Status s = leveldb::DB::Open(options, path + "/meta/", &metadb);
        if (!s.ok()) {
            LOG(ERROR, "[MetaCheck] Open meta on %s failed: %s", path.c_str(), s.ToString().c_str());
            exit(EXIT_FAILURE);
            return;
        }

        std::string version_key(8, '\0');
        version_key.append("version");
        std::string version_str;
        s = metadb->Get(leveldb::ReadOptions(), version_key, &version_str);
        if (s.IsNotFound()) {
            LOG(INFO, "[MetaCheck] Load empty meta %s", path.c_str());
        } else {
            int64_t ns_v = *(reinterpret_cast<int64_t*>(&version_str[0]));
            LOG(INFO, "[MetaCheck] Load namespace %ld on %s", ns_v, path.c_str());
            std::string meta_key(8, '\0');
            meta_key.append("meta");
            std::string meta_str;
            s = metadb->Get(leveldb::ReadOptions(), meta_key, &meta_str);
            if (s.ok()) {
                int cur_version = *(reinterpret_cast<int*>(&meta_str[0]));
                LOG(INFO, "[MetaCheck] %s Load meta version %d", path.c_str(), cur_version);
                if (meta_version != EMPTY_META && cur_version != meta_version) {
                    LOG(ERROR, "Cannot handle this situation!!!");
                    exit(EXIT_FAILURE);
                }
                meta_version = cur_version;
            } else if (s.IsNotFound()) {
                if (meta_version != EMPTY_META && meta_version != 0) {
                    LOG(ERROR, "Cannot handle this situation!!!");
                    exit(EXIT_FAILURE);
                }
                meta_version = 0;
                LOG(INFO, "No meta version %s", path.c_str());
            }
        }
        meta_dbs[path] = metadb;
    }
    if (meta_version == CHUNKSERVER_META_VERSION) {
        LOG(INFO, "[MetaCheck] Chunkserver meta check pass");
    } else if (meta_version == EMPTY_META) {
        LOG(INFO, "[MetaCheck] Chunkserver empty");
        SetChunkserverMetaVersion(meta_dbs);
    } else if (meta_version == 0) {
        ChunkserverMetaV02V1(meta_dbs);
        SetChunkserverMetaVersion(meta_dbs);
    } else {
        LOG(ERROR, "[MetaCheck] Cannot handle this situation!!!");
        exit(EXIT_FAILURE);
    }
    CloseMetaStore(meta_dbs);
}

void ChunkserverMetaV02V1(const std::map<std::string, leveldb::DB*>& meta_dbs) {
    LOG(INFO, "[MetaCheck] Start converting chunkserver meta from verion 0");
    leveldb::DB* src_meta = NULL;
    std::string src_meta_path;
    std::string version_key(8, '\0');
    version_key.append("version");
    std::string version_str;
    for (auto it = meta_dbs.begin(); it != meta_dbs.end(); ++it) {
        leveldb::DB* cur_db = it->second;
        const std::string& cur_path = it->first;
        leveldb::Status s = cur_db->Get(leveldb::ReadOptions(), version_key, &version_str);
        if (s.ok()) {
            src_meta = cur_db;
            src_meta_path = it->first;
            LOG(INFO, "[MetaCheck] Source meta store %s", cur_path.c_str());
            break;
        } else {
            LOG(INFO, "[MetaCheck] No namespace version on %s, %s", cur_path.c_str(), s.ToString().c_str());
        }
    }
    if (!src_meta) {
        LOG(ERROR, "[MetaCheck] Cannot find a valid meta store");
        exit(EXIT_FAILURE);
    }

    leveldb::Iterator* it = src_meta->NewIterator(leveldb::ReadOptions());
    for (it->Seek(std::string(8, '\0') + "version" + '\0'); it->Valid(); it->Next()) {
        BlockMeta meta;
        if (!meta.ParseFromArray(it->value().data(), it->value().size())) {
            LOG(ERROR, "[MetaCheck] Parse BlockMeta failed: key = %s", it->key().ToString().c_str());
            exit(EXIT_FAILURE);
        }
        const std::string& path = meta.store_path();
        auto db_it = meta_dbs.find(path);
        if (db_it == meta_dbs.end()) {
            LOG(WARNING, "[MetaCheck] Cannot find store_path %s", path.c_str());
            continue;
        }
        leveldb::DB* disk_db = db_it->second;
        disk_db->Put(leveldb::WriteOptions(), it->key(), it->value());
        if (path != src_meta_path) {
            src_meta->Delete(leveldb::WriteOptions(), it->key());
        }
    }
    for (auto it = meta_dbs.begin(); it != meta_dbs.end(); ++it) {
        leveldb::DB* ldb = it->second;
        ldb->Put(leveldb::WriteOptions(), version_key, version_str);
    }
    delete it;
}

void SetChunkserverMetaVersion(const std::map<std::string, leveldb::DB*>& meta_dbs) {
    for (auto it = meta_dbs.begin(); it != meta_dbs.end(); ++it) {
        leveldb::DB* ldb = it->second;
        std::string meta_key(8, '\0');
        meta_key.append("meta");
        std::string meta_str(4, '\0');
        *(reinterpret_cast<int*>(&meta_str[0])) = CHUNKSERVER_META_VERSION;
        leveldb::Status s = ldb->Put(leveldb::WriteOptions(), meta_key, meta_str);
        if (!s.ok()) {
            LOG(ERROR, "[MetaCheck] Put meta failed %s", it->first.c_str());
            exit(EXIT_FAILURE);
        }
        LOG(INFO, "[MetaCheck] Set meta version %s = %d", it->first.c_str(), CHUNKSERVER_META_VERSION);
    }
}

void CloseMetaStore(const std::map<std::string, leveldb::DB*>& meta_dbs) {
    for (auto it = meta_dbs.begin(); it != meta_dbs.end(); ++it) {
        delete it->second;
    }
}

} // namespace bfs
} // namespace baidu<commit_msg>Small fix<commit_after>// Copyright (c) 2016, Baidu.com, Inc. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include <string>
#include <map>

#include <gflags/gflags.h>
#include <leveldb/db.h>

#include <common/string_util.h>
#include <common/logging.h>

#include "proto/block.pb.h"

#include "utils/meta_converter.h"

namespace baidu {
namespace bfs {

const int CHUNKSERVER_META_VERSION = 1;

const int EMPTY_META = -1;

void CheckChunkserverMeta(const std::vector<std::string>& store_path_list) {
    std::map<std::string, leveldb::DB*> meta_dbs;
    int meta_version = EMPTY_META;
    for (size_t i = 0; i < store_path_list.size(); ++i) {
        const std::string& path = store_path_list[i];
        leveldb::Options options;
        options.create_if_missing = true;
        leveldb::DB* metadb;
        leveldb::Status s = leveldb::DB::Open(options, path + "/meta/", &metadb);
        if (!s.ok()) {
            LOG(ERROR, "[MetaCheck] Open meta on %s failed: %s", path.c_str(), s.ToString().c_str());
            exit(EXIT_FAILURE);
            return;
        }

        std::string version_key(8, '\0');
        version_key.append("version");
        std::string version_str;
        s = metadb->Get(leveldb::ReadOptions(), version_key, &version_str);
        if (s.IsNotFound()) {
            LOG(INFO, "[MetaCheck] Load empty meta %s", path.c_str());
        } else {
            int64_t ns_v = *(reinterpret_cast<int64_t*>(&version_str[0]));
            LOG(INFO, "[MetaCheck] Load namespace %ld on %s", ns_v, path.c_str());
            std::string meta_key(8, '\0');
            meta_key.append("meta");
            std::string meta_str;
            s = metadb->Get(leveldb::ReadOptions(), meta_key, &meta_str);
            if (s.ok()) {
                int cur_version = *(reinterpret_cast<int*>(&meta_str[0]));
                LOG(INFO, "[MetaCheck] %s Load meta version %d", path.c_str(), cur_version);
                if (meta_version != EMPTY_META && cur_version != meta_version) {
                    LOG(ERROR, "Cannot handle this situation!!!");
                    exit(EXIT_FAILURE);
                }
                meta_version = cur_version;
            } else if (s.IsNotFound()) {
                if (meta_version != EMPTY_META && meta_version != 0) {
                    LOG(ERROR, "Cannot handle this situation!!!");
                    exit(EXIT_FAILURE);
                }
                meta_version = 0;
                LOG(INFO, "No meta version %s", path.c_str());
            }
        }
        meta_dbs[path] = metadb;
    }
    if (meta_version == CHUNKSERVER_META_VERSION) {
        LOG(INFO, "[MetaCheck] Chunkserver meta check pass");
    } else if (meta_version == EMPTY_META) {
        LOG(INFO, "[MetaCheck] Chunkserver empty");
        SetChunkserverMetaVersion(meta_dbs);
    } else if (meta_version == 0) {
        ChunkserverMetaV02V1(meta_dbs);
        SetChunkserverMetaVersion(meta_dbs);
    } else {
        LOG(ERROR, "[MetaCheck] Cannot handle this situation!!!");
        exit(EXIT_FAILURE);
    }
    CloseMetaStore(meta_dbs);
}

void ChunkserverMetaV02V1(const std::map<std::string, leveldb::DB*>& meta_dbs) {
    LOG(INFO, "[MetaCheck] Start converting chunkserver meta from verion 0");
    leveldb::DB* src_meta = NULL;
    std::string src_meta_path;
    std::string version_key(8, '\0');
    version_key.append("version");
    std::string version_str;
    for (auto it = meta_dbs.begin(); it != meta_dbs.end(); ++it) {
        leveldb::DB* cur_db = it->second;
        const std::string& cur_path = it->first;
        leveldb::Status s = cur_db->Get(leveldb::ReadOptions(), version_key, &version_str);
        if (s.ok()) {
            src_meta = cur_db;
            src_meta_path = it->first;
            LOG(INFO, "[MetaCheck] Source meta store %s", cur_path.c_str());
            break;
        } else {
            LOG(INFO, "[MetaCheck] No namespace version on %s, %s", cur_path.c_str(), s.ToString().c_str());
        }
    }
    if (!src_meta) {
        LOG(ERROR, "[MetaCheck] Cannot find a valid meta store");
        exit(EXIT_FAILURE);
    }

    leveldb::Iterator* it = src_meta->NewIterator(leveldb::ReadOptions());
    for (it->Seek(std::string(8, '\0') + "version" + '\0'); it->Valid(); it->Next()) {
        BlockMeta meta;
        if (!meta.ParseFromArray(it->value().data(), it->value().size())) {
            LOG(ERROR, "[MetaCheck] Parse BlockMeta failed: key = %s", it->key().ToString().c_str());
            exit(EXIT_FAILURE);
        }
        const std::string& path = meta.store_path();
        auto db_it = meta_dbs.find(path);
        if (db_it == meta_dbs.end()) {
            src_meta->Delete(leveldb::WriteOptions(), it->key());
            LOG(WARNING, "[MetaCheck] Cannot find store_path %s", path.c_str());
            continue;
        }
        leveldb::DB* disk_db = db_it->second;
        disk_db->Put(leveldb::WriteOptions(), it->key(), it->value());
        if (path != src_meta_path) {
            src_meta->Delete(leveldb::WriteOptions(), it->key());
        }
    }
    for (auto it = meta_dbs.begin(); it != meta_dbs.end(); ++it) {
        leveldb::DB* ldb = it->second;
        ldb->Put(leveldb::WriteOptions(), version_key, version_str);
    }
    delete it;
}

void SetChunkserverMetaVersion(const std::map<std::string, leveldb::DB*>& meta_dbs) {
    for (auto it = meta_dbs.begin(); it != meta_dbs.end(); ++it) {
        leveldb::DB* ldb = it->second;
        std::string meta_key(8, '\0');
        meta_key.append("meta");
        std::string meta_str(4, '\0');
        *(reinterpret_cast<int*>(&meta_str[0])) = CHUNKSERVER_META_VERSION;
        leveldb::Status s = ldb->Put(leveldb::WriteOptions(), meta_key, meta_str);
        if (!s.ok()) {
            LOG(ERROR, "[MetaCheck] Put meta failed %s", it->first.c_str());
            exit(EXIT_FAILURE);
        }
        LOG(INFO, "[MetaCheck] Set meta version %s = %d", it->first.c_str(), CHUNKSERVER_META_VERSION);
    }
}

void CloseMetaStore(const std::map<std::string, leveldb::DB*>& meta_dbs) {
    for (auto it = meta_dbs.begin(); it != meta_dbs.end(); ++it) {
        delete it->second;
    }
}

} // namespace bfs
} // namespace baidu<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

// [[CITE]] Tarjan's strongly connected components algorithm
// Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146-160, doi:10.1137/0201010
// http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include <set>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SccWorker
{
	RTLIL::Design *design;
	RTLIL::Module *module;
	SigMap sigmap;
	CellTypes ct;

	std::set<RTLIL::Cell*> workQueue;
	std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
	std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;

	std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
	std::map<RTLIL::Cell*, int> cellDepth;
	std::set<RTLIL::Cell*> cellsOnStack;
	std::vector<RTLIL::Cell*> cellStack;
	int labelCounter;

	std::map<RTLIL::Cell*, int> cell2scc;
	std::vector<std::set<RTLIL::Cell*>> sccList;

	void run(RTLIL::Cell *cell, int depth, int maxDepth)
	{
		log_assert(workQueue.count(cell) > 0);

		workQueue.erase(cell);
		cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
		labelCounter++;

		cellsOnStack.insert(cell);
		cellStack.push_back(cell);

		if (maxDepth >= 0)
			cellDepth[cell] = depth;

		for (auto nextCell : cellToNextCell[cell])
			if (cellLabels.count(nextCell) == 0) {
				run(nextCell, depth+1, maxDepth);
				cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			} else
			if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
					cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			}

		if (cellLabels[cell].first == cellLabels[cell].second)
		{
			if (cellStack.back() == cell)
			{
				cellStack.pop_back();
				cellsOnStack.erase(cell);
			}
			else
			{
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				while (cellsOnStack.count(cell) > 0) {
					RTLIL::Cell *c = cellStack.back();
					cellStack.pop_back();
					cellsOnStack.erase(c);
					log(" %s", RTLIL::id2cstr(c->name));
					cell2scc[c] = sccList.size();
					scc.insert(c);
				}
				sccList.push_back(scc);
				log("\n");
			}
		}
	}

	SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, int maxDepth) :
			design(design), module(module), sigmap(module)
	{
		if (module->processes.size() > 0) {
			log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
			return;
		}

		if (allCellTypes) {
			ct.setup(design);
		} else {
			ct.setup_internals();
			ct.setup_stdcells();
		}

		SigPool selectedSignals;
		SigSet<RTLIL::Cell*> sigToNextCells;

		for (auto &it : module->wires_)
			if (design->selected(module, it.second))
				selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));

		for (auto &it : module->cells_)
		{
			RTLIL::Cell *cell = it.second;

			if (!design->selected(module, cell))
				continue;

			if (!allCellTypes && !ct.cell_known(cell->type))
				continue;

			workQueue.insert(cell);

			RTLIL::SigSpec inputSignals, outputSignals;

			for (auto &conn : cell->connections())
			{
				bool isInput = true, isOutput = true;

				if (ct.cell_known(cell->type)) {
					isInput = ct.cell_input(cell->type, conn.first);
					isOutput = ct.cell_output(cell->type, conn.first);
				}

				RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second));
				sig.sort_and_unify();

				if (isInput)
					inputSignals.append(sig);
				if (isOutput)
					outputSignals.append(sig);
			}

			inputSignals.sort_and_unify();
			outputSignals.sort_and_unify();

			cellToPrevSig[cell] = inputSignals;
			cellToNextSig[cell] = outputSignals;
			sigToNextCells.insert(inputSignals, cell);
		}

		for (auto cell : workQueue)
		{
			cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);

			if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				log(" %s", RTLIL::id2cstr(cell->name));
				cell2scc[cell] = sccList.size();
				scc.insert(cell);
				sccList.push_back(scc);
				log("\n");
			}
		}

		labelCounter = 0;
		cellLabels.clear();

		while (!workQueue.empty())
		{
			RTLIL::Cell *cell = *workQueue.begin();
			log_assert(cellStack.size() == 0);
			cellDepth.clear();

			run(cell, 0, maxDepth);
		}

		log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
	}

	void select(RTLIL::Selection &sel)
	{
		for (int i = 0; i < int(sccList.size()); i++)
		{
			std::set<RTLIL::Cell*> &cells = sccList[i];
			RTLIL::SigSpec prevsig, nextsig, sig;

			for (auto cell : cells) {
				sel.selected_members[module->name].insert(cell->name);
				prevsig.append(cellToPrevSig[cell]);
				nextsig.append(cellToNextSig[cell]);
			}

			prevsig.sort_and_unify();
			nextsig.sort_and_unify();
			sig = prevsig.extract(nextsig);

			for (auto &chunk : sig.chunks())
				if (chunk.wire != NULL)
					sel.selected_members[module->name].insert(chunk.wire->name);
		}
	}
};

struct SccPass : public Pass {
	SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    scc [options] [selection]\n");
		log("\n");
		log("This command identifies strongly connected components (aka logic loops) in the\n");
		log("design.\n");
		log("\n");
		log("    -expect <num>\n");
		log("        expect to find exactly <num> SSCs. A different number of SSCs will\n");
		log("        produce an error.\n");
		log("\n");
		log("    -max_depth <num>\n");
		log("        limit to loops not longer than the specified number of cells. This\n");
		log("        can e.g. be useful in identifying small local loops in a module that\n");
		log("        implements one large SCC.\n");
		log("\n");
		log("    -nofeedback\n");
		log("        do not count cells that have their output fed back into one of their\n");
		log("        inputs as single-cell scc.\n");
		log("\n");
		log("    -all_cell_types\n");
		log("        Usually this command only considers internal non-memory cells. With\n");
		log("        this option set, all cells are considered. For unknown cells all ports\n");
		log("        are assumed to be bidirectional 'inout' ports.\n");
		log("\n");
		log("    -set_attr <name> <value>\n");
		log("        set the specified attribute on all cells that are part of a logic\n");
		log("        loop. the special token {} in the value is replaced with a unique\n");
		log("        identifier for the logic loop.\n");
		log("\n");
		log("    -select\n");
		log("        replace the current selection with a selection of all cells and wires\n");
		log("        that are part of a found logic loop\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		std::map<std::string, std::string> setAttr;
		bool allCellTypes = false;
		bool selectMode = false;
		bool nofeedbackMode = false;
		int maxDepth = -1;
		int expect = -1;

		log_header(design, "Executing SCC pass (detecting logic loops).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-max_depth" && argidx+1 < args.size()) {
				maxDepth = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-expect" && argidx+1 < args.size()) {
				expect = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-nofeedback") {
				nofeedbackMode = true;
				continue;
			}
			if (args[argidx] == "-all_cell_types") {
				allCellTypes = true;
				continue;
			}
			if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
				setAttr[args[argidx+1]] = args[argidx+2];
				argidx += 2;
				continue;
			}
			if (args[argidx] == "-select") {
				selectMode = true;
				continue;
			}
			break;
		}
		int origSelectPos = design->selection_stack.size() - 1;
		extra_args(args, argidx, design);

		RTLIL::Selection newSelection(false);
		int scc_counter = 0;

		for (auto &mod_it : design->modules_)
			if (design->selected(mod_it.second))
			{
				SccWorker worker(design, mod_it.second, nofeedbackMode, allCellTypes, maxDepth);

				if (!setAttr.empty())
				{
					for (const auto &cells : worker.sccList)
					{
						for (auto attr : setAttr)
						{
							IdString attr_name(RTLIL::escape_id(attr.first));
							string attr_valstr = attr.second;
							string index = stringf("%d", scc_counter);

							for (size_t pos = 0; (pos = attr_valstr.find("{}", pos)) != string::npos; pos += index.size())
								attr_valstr.replace(pos, 2, index);

							Const attr_value(attr_valstr);

							for (auto cell : cells)
								cell->attributes[attr_name] = attr_value;
						}

						scc_counter++;
					}
				}
				else
				{
					scc_counter += GetSize(worker.sccList);
				}

				if (selectMode)
					worker.select(newSelection);
			}

		if (expect >= 0) {
			if (scc_counter == expect)
				log("Found and expected %d SCCs.\n", scc_counter);
			else
				log_error("Found %d SCCs but expected %d.\n", scc_counter, expect);
		} else
			log("Found %d SCCs.\n", scc_counter);

		if (selectMode) {
			log_assert(origSelectPos >= 0);
			design->selection_stack[origSelectPos] = newSelection;
			design->selection_stack[origSelectPos].optimize(design);
		}
	}
} SccPass;

PRIVATE_NAMESPACE_END
<commit_msg>scc command to ignore blackboxes<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

// [[CITE]] Tarjan's strongly connected components algorithm
// Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146-160, doi:10.1137/0201010
// http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include <set>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SccWorker
{
	RTLIL::Design *design;
	RTLIL::Module *module;
	SigMap sigmap;
	CellTypes ct;

	std::set<RTLIL::Cell*> workQueue;
	std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
	std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;

	std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
	std::map<RTLIL::Cell*, int> cellDepth;
	std::set<RTLIL::Cell*> cellsOnStack;
	std::vector<RTLIL::Cell*> cellStack;
	int labelCounter;

	std::map<RTLIL::Cell*, int> cell2scc;
	std::vector<std::set<RTLIL::Cell*>> sccList;

	void run(RTLIL::Cell *cell, int depth, int maxDepth)
	{
		log_assert(workQueue.count(cell) > 0);

		workQueue.erase(cell);
		cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
		labelCounter++;

		cellsOnStack.insert(cell);
		cellStack.push_back(cell);

		if (maxDepth >= 0)
			cellDepth[cell] = depth;

		for (auto nextCell : cellToNextCell[cell])
			if (cellLabels.count(nextCell) == 0) {
				run(nextCell, depth+1, maxDepth);
				cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			} else
			if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
					cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			}

		if (cellLabels[cell].first == cellLabels[cell].second)
		{
			if (cellStack.back() == cell)
			{
				cellStack.pop_back();
				cellsOnStack.erase(cell);
			}
			else
			{
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				while (cellsOnStack.count(cell) > 0) {
					RTLIL::Cell *c = cellStack.back();
					cellStack.pop_back();
					cellsOnStack.erase(c);
					log(" %s", RTLIL::id2cstr(c->name));
					cell2scc[c] = sccList.size();
					scc.insert(c);
				}
				sccList.push_back(scc);
				log("\n");
			}
		}
	}

	SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, int maxDepth) :
			design(design), module(module), sigmap(module)
	{
		if (module->processes.size() > 0) {
			log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
			return;
		}

		if (allCellTypes) {
			ct.setup(design);
		} else {
			ct.setup_internals();
			ct.setup_stdcells();
		}

		SigPool selectedSignals;
		SigSet<RTLIL::Cell*> sigToNextCells;

		for (auto &it : module->wires_)
			if (design->selected(module, it.second))
				selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));

		for (auto &it : module->cells_)
		{
			RTLIL::Cell *cell = it.second;

			if (!design->selected(module, cell))
				continue;

			if (!allCellTypes && !ct.cell_known(cell->type))
				continue;

			workQueue.insert(cell);

			RTLIL::SigSpec inputSignals, outputSignals;

			for (auto &conn : cell->connections())
			{
				bool isInput = true, isOutput = true;

				if (ct.cell_known(cell->type)) {
					isInput = ct.cell_input(cell->type, conn.first);
					isOutput = ct.cell_output(cell->type, conn.first);
				}

				RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second));
				sig.sort_and_unify();

				if (isInput)
					inputSignals.append(sig);
				if (isOutput)
					outputSignals.append(sig);
			}

			inputSignals.sort_and_unify();
			outputSignals.sort_and_unify();

			cellToPrevSig[cell] = inputSignals;
			cellToNextSig[cell] = outputSignals;
			sigToNextCells.insert(inputSignals, cell);
		}

		for (auto cell : workQueue)
		{
			cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);

			if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				log(" %s", RTLIL::id2cstr(cell->name));
				cell2scc[cell] = sccList.size();
				scc.insert(cell);
				sccList.push_back(scc);
				log("\n");
			}
		}

		labelCounter = 0;
		cellLabels.clear();

		while (!workQueue.empty())
		{
			RTLIL::Cell *cell = *workQueue.begin();
			log_assert(cellStack.size() == 0);
			cellDepth.clear();

			run(cell, 0, maxDepth);
		}

		log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
	}

	void select(RTLIL::Selection &sel)
	{
		for (int i = 0; i < int(sccList.size()); i++)
		{
			std::set<RTLIL::Cell*> &cells = sccList[i];
			RTLIL::SigSpec prevsig, nextsig, sig;

			for (auto cell : cells) {
				sel.selected_members[module->name].insert(cell->name);
				prevsig.append(cellToPrevSig[cell]);
				nextsig.append(cellToNextSig[cell]);
			}

			prevsig.sort_and_unify();
			nextsig.sort_and_unify();
			sig = prevsig.extract(nextsig);

			for (auto &chunk : sig.chunks())
				if (chunk.wire != NULL)
					sel.selected_members[module->name].insert(chunk.wire->name);
		}
	}
};

struct SccPass : public Pass {
	SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    scc [options] [selection]\n");
		log("\n");
		log("This command identifies strongly connected components (aka logic loops) in the\n");
		log("design.\n");
		log("\n");
		log("    -expect <num>\n");
		log("        expect to find exactly <num> SSCs. A different number of SSCs will\n");
		log("        produce an error.\n");
		log("\n");
		log("    -max_depth <num>\n");
		log("        limit to loops not longer than the specified number of cells. This\n");
		log("        can e.g. be useful in identifying small local loops in a module that\n");
		log("        implements one large SCC.\n");
		log("\n");
		log("    -nofeedback\n");
		log("        do not count cells that have their output fed back into one of their\n");
		log("        inputs as single-cell scc.\n");
		log("\n");
		log("    -all_cell_types\n");
		log("        Usually this command only considers internal non-memory cells. With\n");
		log("        this option set, all cells are considered. For unknown cells all ports\n");
		log("        are assumed to be bidirectional 'inout' ports.\n");
		log("\n");
		log("    -set_attr <name> <value>\n");
		log("        set the specified attribute on all cells that are part of a logic\n");
		log("        loop. the special token {} in the value is replaced with a unique\n");
		log("        identifier for the logic loop.\n");
		log("\n");
		log("    -select\n");
		log("        replace the current selection with a selection of all cells and wires\n");
		log("        that are part of a found logic loop\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		std::map<std::string, std::string> setAttr;
		bool allCellTypes = false;
		bool selectMode = false;
		bool nofeedbackMode = false;
		int maxDepth = -1;
		int expect = -1;

		log_header(design, "Executing SCC pass (detecting logic loops).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-max_depth" && argidx+1 < args.size()) {
				maxDepth = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-expect" && argidx+1 < args.size()) {
				expect = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-nofeedback") {
				nofeedbackMode = true;
				continue;
			}
			if (args[argidx] == "-all_cell_types") {
				allCellTypes = true;
				continue;
			}
			if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
				setAttr[args[argidx+1]] = args[argidx+2];
				argidx += 2;
				continue;
			}
			if (args[argidx] == "-select") {
				selectMode = true;
				continue;
			}
			break;
		}
		int origSelectPos = design->selection_stack.size() - 1;
		extra_args(args, argidx, design);

		RTLIL::Selection newSelection(false);
		int scc_counter = 0;

		for (auto mod : design->modules())
			if (!mod->get_blackbox_attribute() && design->selected(mod))
			{
				SccWorker worker(design, mod, nofeedbackMode, allCellTypes, maxDepth);

				if (!setAttr.empty())
				{
					for (const auto &cells : worker.sccList)
					{
						for (auto attr : setAttr)
						{
							IdString attr_name(RTLIL::escape_id(attr.first));
							string attr_valstr = attr.second;
							string index = stringf("%d", scc_counter);

							for (size_t pos = 0; (pos = attr_valstr.find("{}", pos)) != string::npos; pos += index.size())
								attr_valstr.replace(pos, 2, index);

							Const attr_value(attr_valstr);

							for (auto cell : cells)
								cell->attributes[attr_name] = attr_value;
						}

						scc_counter++;
					}
				}
				else
				{
					scc_counter += GetSize(worker.sccList);
				}

				if (selectMode)
					worker.select(newSelection);
			}

		if (expect >= 0) {
			if (scc_counter == expect)
				log("Found and expected %d SCCs.\n", scc_counter);
			else
				log_error("Found %d SCCs but expected %d.\n", scc_counter, expect);
		} else
			log("Found %d SCCs.\n", scc_counter);

		if (selectMode) {
			log_assert(origSelectPos >= 0);
			design->selection_stack[origSelectPos] = newSelection;
			design->selection_stack[origSelectPos].optimize(design);
		}
	}
} SccPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "token.h"
#include "token_exception.h"
#include "tokenreader.h"

using namespace std;

/* tokenreader reads a file formatted with s-expressions. examples:
 * (hello)
 * (hello world)
 * (hello "world")
 * (hello (world))
 * (hello (world hi))
 */
TokenReader::TokenReader( const char * file ){
	ifile.open( file );
	myfile = string( file );
	ifile >> noskipws;
	// cout<<"Opened "<<file<<endl;
}

TokenReader::TokenReader( const string & file ){
	ifile.open( file.c_str() );
	myfile = file;
	ifile >> noskipws;
}

TokenReader::~TokenReader(){
	ifile.close();

	/* tokenreader giveth, and tokenreader taketh */
	for ( vector< Token * >::iterator it = my_tokens.begin(); it != my_tokens.end(); it++ ){
		delete *it;
	}
}

Token * TokenReader::readToken() throw( TokenException ){

	if ( !ifile ){
            throw TokenException( string("Could not open ") + myfile );
        }
	// Token * t;

	// string token_string;

	char open_paren = 'x';
	int parens = 1;
	while ( ifile.good() && open_paren != '(' ){
		ifile >> open_paren;
	}
	// token_string += '(';

	Token * cur_token = new Token();
	cur_token->setFile( myfile );
	my_tokens.push_back( cur_token );
	Token * first = cur_token;
	vector< Token * > token_stack;
	token_stack.push_back( cur_token );

	char n;
	string cur_string = "";
	// while ( parens != 0 ){

	/* in_quote is true if a " is read and before another " is read */
	bool in_quote = false;

	/* escaped unconditionally adds the next character to the string */
	bool escaped = false;
	while ( !token_stack.empty() ){
		if ( !ifile ){
			cout<<__FILE__<<": "<<myfile<<" is bad. Open parens "<<parens<<endl;
			// cout<<"Dump: "<< token_string << "Last token = [" << n << "]" << (int)n << endl;
			first->print( " " );
			throw TokenException("Wrong number of parentheses");
		}
		// char n;
		// slow as we go
		ifile >> n;

		const char * alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_!";
		const char * nonalpha = " ;()#\"";
		// cout<<"Alpha char: "<<n<<endl;

		if ( escaped ){
                    switch (n){
                        case 'n' : {
                            cur_string += "\n";
                            break;
                        }
                        default : {
                            cur_string += n;
                            break;
                        }
                    }
                    escaped = false;
                    continue;
		}

		if ( n == '\\' ){
			escaped = true;
			continue;
		}

		if ( in_quote ){
			if ( n == '"' ){
				in_quote = false;

				Token * sub = new Token( cur_string, false );
				sub->setParent( cur_token );
				cur_token->addToken( sub );
				cur_string = "";

			} else
				cur_string += n;

		} else {
			if ( n == '"' )
				in_quote = true;

			if ( strchr( alpha, n ) != NULL ){
				cur_string += n;
			} else if ( cur_string != "" && strchr( nonalpha, n ) != NULL ){
				// cout<<"Made new token "<<cur_string<<endl;
				Token * sub = new Token( cur_string, false );
				sub->setParent( cur_token );
				cur_token->addToken( sub );
				cur_string = "";
			}
		}

		if ( n == '#' || n == ';' ){
			while ( n != '\n' && !ifile.eof() ){
				ifile >> n;
			}
			continue;
		} else if ( n == '(' ){
			Token * another = new Token();
			another->setParent( cur_token );
			cur_token->addToken( another );
			cur_token = another;
			token_stack.push_back( cur_token );
			/*
			parens++;
			cout<<"Inc Parens is "<<parens<<endl;
			*/
		} else if ( n == ')' ){

			if ( token_stack.empty() ){
				cout<<"Stack is empty"<<endl;
				throw TokenException("Stack is empty");
			}
			token_stack.pop_back();
			if ( ! token_stack.empty() ){
				cur_token = token_stack.back();
			}
		}
	}

	// first->print("");
	first->finalize();
	return first;

}

<commit_msg>ignore tokens with ;@ or #@<commit_after>#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>

#include "token.h"
#include "token_exception.h"
#include "tokenreader.h"

using namespace std;

/* tokenreader reads a file formatted with s-expressions. examples:
 * (hello)
 * (hello world)
 * (hello "world")
 * (hello (world))
 * (hello (world hi))
 */
TokenReader::TokenReader( const char * file ){
	ifile.open( file );
	myfile = string( file );
	ifile >> noskipws;
	// cout<<"Opened "<<file<<endl;
}

TokenReader::TokenReader( const string & file ){
	ifile.open( file.c_str() );
	myfile = file;
	ifile >> noskipws;
}

TokenReader::~TokenReader(){
	ifile.close();

	/* tokenreader giveth, and tokenreader taketh */
	for ( vector< Token * >::iterator it = my_tokens.begin(); it != my_tokens.end(); it++ ){
		delete *it;
	}
}

Token * TokenReader::readToken() throw( TokenException ){

	if ( !ifile ){
            throw TokenException( string("Could not open ") + myfile );
        }
	// Token * t;

	// string token_string;

	char open_paren = 'x';
	int parens = 1;
	while ( ifile.good() && open_paren != '(' ){
		ifile >> open_paren;
	}
	// token_string += '(';

	Token * cur_token = new Token();
	cur_token->setFile( myfile );
	my_tokens.push_back( cur_token );
	Token * first = cur_token;
	vector< Token * > token_stack;
        /* tokens that were ignored using ;@, and should be deleted */
        vector<Token*> ignore_list;
	token_stack.push_back( cur_token );

        /* when a ;@ is seen, read the next s-expression but throw it away */
        bool do_ignore = false;

	char n;
	string cur_string = "";
	// while ( parens != 0 ){

	/* in_quote is true if a " is read and before another " is read */
	bool in_quote = false;

	/* escaped unconditionally adds the next character to the string */
	bool escaped = false;
	while ( !token_stack.empty() ){
		if ( !ifile ){
			cout<<__FILE__<<": "<<myfile<<" is bad. Open parens "<<parens<<endl;
			// cout<<"Dump: "<< token_string << "Last token = [" << n << "]" << (int)n << endl;
			first->print( " " );
			throw TokenException("Wrong number of parentheses");
		}
		// char n;
		// slow as we go
		ifile >> n;

		const char * alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./-_!";
		const char * nonalpha = " ;()#\"";
		// cout<<"Alpha char: "<<n<<endl;

		if ( escaped ){
                    switch (n){
                        case 'n' : {
                            cur_string += "\n";
                            break;
                        }
                        default : {
                            cur_string += n;
                            break;
                        }
                    }
                    escaped = false;
                    continue;
		}

		if ( n == '\\' ){
			escaped = true;
			continue;
		}

		if ( in_quote ){
			if ( n == '"' ){
				in_quote = false;

				Token * sub = new Token( cur_string, false );
				sub->setParent( cur_token );
                                if (do_ignore){
                                    ignore_list.push_back(sub);
                                    do_ignore = false;
                                } else {
                                    cur_token->addToken( sub );
                                }
				cur_string = "";

			} else
				cur_string += n;

		} else {
			if ( n == '"' )
				in_quote = true;

			if ( strchr( alpha, n ) != NULL ){
				cur_string += n;
			} else if ( cur_string != "" && strchr( nonalpha, n ) != NULL ){
				// cout<<"Made new token "<<cur_string<<endl;
				Token * sub = new Token( cur_string, false );
				sub->setParent( cur_token );
                                if (do_ignore){
                                    do_ignore = false;
                                    ignore_list.push_back(sub);
                                } else {
                                    cur_token->addToken( sub );
                                }
				cur_string = "";
			}
		}

		if ( n == '#' || n == ';' ){
                    ifile >> n;
                    if (n == '@'){
                        do_ignore = true;
                    } else {
			while ( n != '\n' && !ifile.eof() ){
				ifile >> n;
			}
			continue;
                    }
		} else if ( n == '(' ){
			Token * another = new Token();
			another->setParent( cur_token );

                        if (do_ignore){
                            ignore_list.push_back(another);
                            do_ignore = false;
                        } else {
                            cur_token->addToken(another);
                        }

			cur_token = another;
			token_stack.push_back( cur_token );
			/*
			parens++;
			cout<<"Inc Parens is "<<parens<<endl;
			*/
		} else if ( n == ')' ){

			if ( token_stack.empty() ){
				cout<<"Stack is empty"<<endl;
				throw TokenException("Stack is empty");
			}
			token_stack.pop_back();

			if ( ! token_stack.empty() ){
				cur_token = token_stack.back();
			}
		}
	}

        for (vector<Token*>::iterator it = ignore_list.begin(); it != ignore_list.end(); it++){
            delete (*it);
        }

	// first->print("");
	first->finalize();
	return first;

}

<|endoftext|>


<commit_before>//******************************************************************
//
// Copyright 2015 Samsung Electronics 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 <iostream>
#include <functional>

#include "mutex"
#include "condition_variable"

#include "RCSDiscoveryManager.h"
#include "RCSRemoteResourceObject.h"
#include "RCSResourceAttributes.h"
#include "RCSAddress.h"
#include "OCPlatform.h"

using namespace OC;
using namespace OIC::Service;

constexpr int CORRECT_INPUT = 1;
constexpr int INCORRECT_INPUT = 2;
constexpr int QUIT_INPUT = 3;

constexpr int REQUEST_TEMP = 1;
constexpr int REQUEST_LIGHT = 2;

std::unique_ptr<RCSDiscoveryTask> discoveryTask = nullptr;
std::shared_ptr<RCSRemoteResourceObject>  resource;

std::string defaultKey = "Temperature";
const std::string relativeUri = OC_RSRVD_WELL_KNOWN_URI;
const std::string multicastAdd = "multi";

std::mutex mtx;
std::condition_variable cond;

void startMonitoring();
void startMonitoring();
void stopMonitoring();
void getAttributeFromRemoteServer();
void setAttributeToRemoteServer();
void startCachingWithoutCallback();
void startCachingWithCallback();
void getResourceCacheState();
void getCachedAttributes();
void getCachedAttribute();
void stopCaching();
void discoverResource();
void cancelDiscovery();
int processUserInput();

enum Menu
{
    START_MONITORING = 1,
    STOP_MONITORING,
    GET_ATTRIBUTE,
    SET_ATTRIBUTE,
    START_CACHING_NO_UPDATE,
    START_CACHING_UPDATE,
    GET_RESOURCE_CACHE_STATE,
    GET_CACHED_ATTRIBUTES,
    GET_CACHED_ATTRIBUTE,
    STOP_CACHING,
    DISCOVERY_RESOURCE,
    CANCEL_DISCOVERY,
    QUIT,
    END_OF_MENU
};

typedef void(*ClientMenuHandler)();
typedef int ReturnValue;

struct ClientMenu
{
    Menu m_menu;
    ClientMenuHandler m_handler;
    ReturnValue m_result;
};

ClientMenu clientMenu[] = {
        {Menu::START_MONITORING, startMonitoring, CORRECT_INPUT},
        {Menu::STOP_MONITORING, stopMonitoring, CORRECT_INPUT},
        {Menu::GET_ATTRIBUTE, getAttributeFromRemoteServer, CORRECT_INPUT},
        {Menu::SET_ATTRIBUTE, setAttributeToRemoteServer, CORRECT_INPUT},
        {Menu::START_CACHING_NO_UPDATE, startCachingWithoutCallback, CORRECT_INPUT},
        {Menu::START_CACHING_UPDATE, startCachingWithCallback, CORRECT_INPUT},
        {Menu::GET_RESOURCE_CACHE_STATE, getResourceCacheState, CORRECT_INPUT},
        {Menu::GET_CACHED_ATTRIBUTES, getCachedAttributes, CORRECT_INPUT},
        {Menu::GET_CACHED_ATTRIBUTE, getCachedAttribute, CORRECT_INPUT},
        {Menu::STOP_CACHING, stopCaching, CORRECT_INPUT},
        {Menu::DISCOVERY_RESOURCE, discoverResource, CORRECT_INPUT},
        {Menu::CANCEL_DISCOVERY, cancelDiscovery, CORRECT_INPUT},
        {Menu::QUIT, [](){}, QUIT_INPUT},
        {Menu::END_OF_MENU, nullptr, INCORRECT_INPUT}
    };

void onResourceDiscovered(std::shared_ptr<RCSRemoteResourceObject> discoveredResource)
{
    std::cout << "onResourceDiscovered callback :: " << std::endl;
    std::string resourceURI = discoveredResource->getUri();
    std::string hostAddress = discoveredResource->getAddress();

    std::cout << resourceURI << std::endl;
    std::cout << hostAddress << std::endl;

    resource = discoveredResource;
}

void onResourceStateChanged(const ResourceState& resourceState)
{
    std::cout << "onResourceStateChanged callback" << std::endl;

    switch(resourceState)
    {
        case ResourceState::NONE:
            std::cout << "\tState changed to : NOT_MONITORING" << std::endl;
            break;

        case ResourceState::ALIVE:
            std::cout << "\tState changed to : ALIVE" << std::endl;
            break;

        case ResourceState::REQUESTED:
            std::cout << "\tState changed to : REQUESTED" << std::endl;
            break;

        case ResourceState::LOST_SIGNAL:
            std::cout << "\tState changed to : LOST_SIGNAL" << std::endl;
            resource = nullptr;
            break;

        case ResourceState::DESTROYED:
            std::cout << "\tState changed to : DESTROYED" << std::endl;
            break;
    }
}

void onCacheUpdated(const RCSResourceAttributes& attributes)
{
    std::cout << "onCacheUpdated callback" << std::endl;

    if (attributes.empty())
    {
        std::cout << "\tAttribute is Empty" << std::endl;
        return;
    }

    for(const auto& attr : attributes)
    {
        std::cout << "\tkey : " << attr.key() << std::endl
                  << "\tvalue : " << attr.value().toString() << std::endl;
    }
}

void onRemoteAttributesReceivedCallback(const RCSResourceAttributes& attributes)
{
    std::cout << "onRemoteAttributesReceivedCallback callback" << std::endl;

    if (attributes.empty())
    {
        std::cout << "\tAttribute is Empty" << std::endl;
        return;
    }

    for(const auto& attr : attributes)
    {
        std::cout << "\tkey : " << attr.key() << std::endl
                  << "\tvalue : " << attr.value().toString() << std::endl;
    }
}

void displayMenu()
{
    std::cout << std::endl;
    std::cout << "1 :: Start Monitoring" << std::endl;
    std::cout << "2 :: Stop Monitoring" << std::endl;
    std::cout << "3 :: Get Attribute" << std::endl;
    std::cout << "4 :: Set Attribute" << std::endl;
    std::cout << "5 :: Start Caching (No update to Application)" << std::endl;
    std::cout << "6 :: Start Caching (Update the application when data change)"<< std::endl;
    std::cout << "7 :: Get Resource cache State" << std::endl;
    std::cout << "8 :: Get Cached Attributes" << std::endl;
    std::cout << "9 :: Get Cached Attribute"  << std::endl;
    std::cout << "10 :: Stop Caching" << std::endl;
    std::cout << "11 :: Discover Resource" << std::endl;
    std::cout << "12 :: Cancel Discovery" << std::endl;
    std::cout << "13 :: Stop Server" << std::endl;
}

int processUserInput()
{
    int userInput;
    std::cin >> userInput;
    if (std::cin.fail())
    {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        return -1;
    }
    return userInput;
}

void startMonitoring()
{
    if (!resource->isMonitoring())
    {
        resource->startMonitoring(&onResourceStateChanged);
        std::cout << "\tHosting Started..." << std::endl;
    }
    else
    {
        std::cout << "\tAlready Started..." << std::endl;
    }
}

void stopMonitoring()
{
    if (resource->isMonitoring())
    {
        resource->stopMonitoring();
        std::cout << "\tHosting stopped..." << std::endl;
    }
    else
    {
       std::cout << "\tHosting not started..." << std::endl;
    }
}

void getAttributeFromRemoteServer()
{
    resource->getRemoteAttributes(&onRemoteAttributesReceivedCallback);
}

void setAttributeToRemoteServer()
{
    std::string key;
    int value;

    RCSResourceAttributes setAttribute;

    std::cout << "\tEnter the Key you want to set : ";
    std::cin >> key;
    std::cout << "\tEnter the value you want to set :";
    std::cin >> value;

    setAttribute[key] = value;
    resource->setRemoteAttributes(setAttribute,
                                  &onRemoteAttributesReceivedCallback);
}

void startCaching(std::function <void (const RCSResourceAttributes&)>cb)
{
    if (!resource->isCaching())
    {
        if(cb) resource->startCaching(&onCacheUpdated);

        else resource->startCaching();

        std::cout << "\tCaching Started..." << std::endl;
    }
    else
    {
        std::cout << "\tAlready Started Caching..." << std::endl;
    }
}

void startCachingWithoutCallback()
{
    startCaching(nullptr);
}

void startCachingWithCallback()
{
    startCaching(onCacheUpdated);
}

void getResourceCacheState()
{
    switch(resource->getCacheState())
    {
        case CacheState::READY:
            std::cout << "\tCurrent Cache State : " << "CACHE_STATE ::READY" << std::endl;
            break;

        case CacheState::UNREADY:
            std::cout << "\tCurrent Cache State : " << "CACHE_STATE ::UNREADY" << std::endl;
            break;

        case CacheState::LOST_SIGNAL:
            std::cout << "\tCurrent Cache State : " << "CACHE_STATE ::LOST_SIGNAL" << std::endl;
            break;

        case CacheState::NONE:
            std::cout << "\tCurrent Cache State : " << "CACHE_STATE ::NONE" << std::endl;
            break;

        default:
            break;
    }
}

void getCachedAttributes()
{
    try
    {
        if (resource->getCachedAttributes().empty())
        {
            std::cout << "\tReceived cached attribute is empty" << std::endl;
        }
        else
        {
            for(const auto& attr : resource->getCachedAttributes())
            {
                std::cout << "\tkey : " << attr.key() << std::endl
                          << "\tvalue : " << attr.value().toString() << std::endl;
            }
        }
    }
    catch (const BadRequestException& e)
    {
        std::cout << "Exception in getCachedAttributes : " << e.what() << std::endl;
    }
}

void getCachedAttribute()
{
    try
    {
        std::cout << "\tkey : " << defaultKey << std::endl
                  << "\tvalue : " << resource->getCachedAttribute(defaultKey).get< int >()
                  << std::endl;
    }
    catch (const BadRequestException& e)
    {
        std::cout << "Exception in getCachedAttribute : " << e.what() << std::endl;
    }
    catch (const BadGetException& e)
    {
        std::cout << "Exception in getCachedAttribute : " << e.what() << std::endl;
    }
}

void stopCaching()
{
    if(resource->isCaching())
    {
        resource->stopCaching();
        std::cout << "\tCaching stopped..." << std::endl;
    }
    else
    {
        std::cout << "\tCaching not started..." << std::endl;
    }
}

int selectClientMenu(int selectedMenu)
{
    for(int i = 0; clientMenu[i].m_menu != Menu::END_OF_MENU; i++)
    {
        if(clientMenu[i].m_menu == selectedMenu)
        {
            clientMenu[i].m_handler();
            return clientMenu[i].m_result;
        }
    }

    std::cout << "Invalid input, please try again" << std::endl;

    return INCORRECT_INPUT;
}

void process()
{
    while(true)
    {
        displayMenu();

        if(selectClientMenu(processUserInput()) == QUIT_INPUT) break;
    }
}

void platFormConfigure()
{
    PlatformConfig config
    {
        OC::ServiceType::InProc, ModeType::Client, "0.0.0.0", 0, OC::QualityOfService::LowQos
    };
    OCPlatform::Configure(config);
}

void discoverResource()
{
    std::string resourceType;

    std::cout << "========================================================" << std::endl;
    std::cout << "1. Temperature Resource Discovery" << std::endl;
    std::cout << "2. Light Resource Discovery" << std::endl;
    std::cout << "========================================================" << std::endl;

    switch (processUserInput())
    {
    case REQUEST_TEMP:
        resourceType = "core.TemperatureSensor";
        break;
    case REQUEST_LIGHT:
        resourceType = "core.light";
        defaultKey = "Light";
        break;
    default :
        std::cout << "Invalid input, please try again" << std::endl;
        return;
    }

    std::string addressInput;
    std::cout << "========================================================" << std::endl;
    std::cout << "Please input address" << std::endl;
    std::cout << "(want to use multicast -> please input 'multi')" << std::endl;
    std::cout << "========================================================" << std::endl;

    std::cin >> addressInput;

    if(addressInput == multicastAdd)
    {
        discoveryTask = RCSDiscoveryManager::getInstance()->discoverResourceByType(RCSAddress::multicast(),
                relativeUri, resourceType, &onResourceDiscovered);
    }
    else
    {
        discoveryTask = RCSDiscoveryManager::getInstance()->discoverResourceByType(RCSAddress::unicast
                (addressInput), relativeUri, resourceType, &onResourceDiscovered);
    }
}

void cancelDiscovery()
{
    if(!discoveryTask)
    {
        std::cout << "There isn't discovery request..." << std::endl;
        return;
    }
    discoveryTask->cancel();
}

int main()
{
    platFormConfigure();

    try
    {
        process();
    }
    catch (const std::exception& e)
    {
        std::cout << "main exception : " << e.what() << std::endl;
    }

    std::cout << "Stopping the Client" << std::endl;

    return 0;
}
<commit_msg>Adding scope to RCSDiscoveryTask<commit_after>//******************************************************************
//
// Copyright 2015 Samsung Electronics 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 <iostream>
#include <functional>

#include "mutex"
#include "condition_variable"

#include "RCSDiscoveryManager.h"
#include "RCSRemoteResourceObject.h"
#include "RCSResourceAttributes.h"
#include "RCSAddress.h"
#include "OCPlatform.h"

using namespace OC;
using namespace OIC::Service;

constexpr int CORRECT_INPUT = 1;
constexpr int INCORRECT_INPUT = 2;
constexpr int QUIT_INPUT = 3;

constexpr int REQUEST_TEMP = 1;
constexpr int REQUEST_LIGHT = 2;

std::unique_ptr<RCSDiscoveryManager::DiscoveryTask> discoveryTask = nullptr;
std::shared_ptr<RCSRemoteResourceObject>  resource;

std::string defaultKey = "Temperature";
const std::string relativeUri = OC_RSRVD_WELL_KNOWN_URI;
const std::string multicastAdd = "multi";

std::mutex mtx;
std::condition_variable cond;

void startMonitoring();
void startMonitoring();
void stopMonitoring();
void getAttributeFromRemoteServer();
void setAttributeToRemoteServer();
void startCachingWithoutCallback();
void startCachingWithCallback();
void getResourceCacheState();
void getCachedAttributes();
void getCachedAttribute();
void stopCaching();
void discoverResource();
void cancelDiscovery();
int processUserInput();

enum Menu
{
    START_MONITORING = 1,
    STOP_MONITORING,
    GET_ATTRIBUTE,
    SET_ATTRIBUTE,
    START_CACHING_NO_UPDATE,
    START_CACHING_UPDATE,
    GET_RESOURCE_CACHE_STATE,
    GET_CACHED_ATTRIBUTES,
    GET_CACHED_ATTRIBUTE,
    STOP_CACHING,
    DISCOVERY_RESOURCE,
    CANCEL_DISCOVERY,
    QUIT,
    END_OF_MENU
};

typedef void(*ClientMenuHandler)();
typedef int ReturnValue;

struct ClientMenu
{
    Menu m_menu;
    ClientMenuHandler m_handler;
    ReturnValue m_result;
};

ClientMenu clientMenu[] = {
        {Menu::START_MONITORING, startMonitoring, CORRECT_INPUT},
        {Menu::STOP_MONITORING, stopMonitoring, CORRECT_INPUT},
        {Menu::GET_ATTRIBUTE, getAttributeFromRemoteServer, CORRECT_INPUT},
        {Menu::SET_ATTRIBUTE, setAttributeToRemoteServer, CORRECT_INPUT},
        {Menu::START_CACHING_NO_UPDATE, startCachingWithoutCallback, CORRECT_INPUT},
        {Menu::START_CACHING_UPDATE, startCachingWithCallback, CORRECT_INPUT},
        {Menu::GET_RESOURCE_CACHE_STATE, getResourceCacheState, CORRECT_INPUT},
        {Menu::GET_CACHED_ATTRIBUTES, getCachedAttributes, CORRECT_INPUT},
        {Menu::GET_CACHED_ATTRIBUTE, getCachedAttribute, CORRECT_INPUT},
        {Menu::STOP_CACHING, stopCaching, CORRECT_INPUT},
        {Menu::DISCOVERY_RESOURCE, discoverResource, CORRECT_INPUT},
        {Menu::CANCEL_DISCOVERY, cancelDiscovery, CORRECT_INPUT},
        {Menu::QUIT, [](){}, QUIT_INPUT},
        {Menu::END_OF_MENU, nullptr, INCORRECT_INPUT}
    };

void onResourceDiscovered(std::shared_ptr<RCSRemoteResourceObject> discoveredResource)
{
    std::cout << "onResourceDiscovered callback :: " << std::endl;
    std::string resourceURI = discoveredResource->getUri();
    std::string hostAddress = discoveredResource->getAddress();

    std::cout << resourceURI << std::endl;
    std::cout << hostAddress << std::endl;

    resource = discoveredResource;
}

void onResourceStateChanged(const ResourceState& resourceState)
{
    std::cout << "onResourceStateChanged callback" << std::endl;

    switch(resourceState)
    {
        case ResourceState::NONE:
            std::cout << "\tState changed to : NOT_MONITORING" << std::endl;
            break;

        case ResourceState::ALIVE:
            std::cout << "\tState changed to : ALIVE" << std::endl;
            break;

        case ResourceState::REQUESTED:
            std::cout << "\tState changed to : REQUESTED" << std::endl;
            break;

        case ResourceState::LOST_SIGNAL:
            std::cout << "\tState changed to : LOST_SIGNAL" << std::endl;
            resource = nullptr;
            break;

        case ResourceState::DESTROYED:
            std::cout << "\tState changed to : DESTROYED" << std::endl;
            break;
    }
}

void onCacheUpdated(const RCSResourceAttributes& attributes)
{
    std::cout << "onCacheUpdated callback" << std::endl;

    if (attributes.empty())
    {
        std::cout << "\tAttribute is Empty" << std::endl;
        return;
    }

    for(const auto& attr : attributes)
    {
        std::cout << "\tkey : " << attr.key() << std::endl
                  << "\tvalue : " << attr.value().toString() << std::endl;
    }
}

void onRemoteAttributesReceivedCallback(const RCSResourceAttributes& attributes)
{
    std::cout << "onRemoteAttributesReceivedCallback callback" << std::endl;

    if (attributes.empty())
    {
        std::cout << "\tAttribute is Empty" << std::endl;
        return;
    }

    for(const auto& attr : attributes)
    {
        std::cout << "\tkey : " << attr.key() << std::endl
                  << "\tvalue : " << attr.value().toString() << std::endl;
    }
}

void displayMenu()
{
    std::cout << std::endl;
    std::cout << "1 :: Start Monitoring" << std::endl;
    std::cout << "2 :: Stop Monitoring" << std::endl;
    std::cout << "3 :: Get Attribute" << std::endl;
    std::cout << "4 :: Set Attribute" << std::endl;
    std::cout << "5 :: Start Caching (No update to Application)" << std::endl;
    std::cout << "6 :: Start Caching (Update the application when data change)"<< std::endl;
    std::cout << "7 :: Get Resource cache State" << std::endl;
    std::cout << "8 :: Get Cached Attributes" << std::endl;
    std::cout << "9 :: Get Cached Attribute"  << std::endl;
    std::cout << "10 :: Stop Caching" << std::endl;
    std::cout << "11 :: Discover Resource" << std::endl;
    std::cout << "12 :: Cancel Discovery" << std::endl;
    std::cout << "13 :: Stop Server" << std::endl;
}

int processUserInput()
{
    int userInput;
    std::cin >> userInput;
    if (std::cin.fail())
    {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        return -1;
    }
    return userInput;
}

void startMonitoring()
{
    if (!resource->isMonitoring())
    {
        resource->startMonitoring(&onResourceStateChanged);
        std::cout << "\tHosting Started..." << std::endl;
    }
    else
    {
        std::cout << "\tAlready Started..." << std::endl;
    }
}

void stopMonitoring()
{
    if (resource->isMonitoring())
    {
        resource->stopMonitoring();
        std::cout << "\tHosting stopped..." << std::endl;
    }
    else
    {
       std::cout << "\tHosting not started..." << std::endl;
    }
}

void getAttributeFromRemoteServer()
{
    resource->getRemoteAttributes(&onRemoteAttributesReceivedCallback);
}

void setAttributeToRemoteServer()
{
    std::string key;
    int value;

    RCSResourceAttributes setAttribute;

    std::cout << "\tEnter the Key you want to set : ";
    std::cin >> key;
    std::cout << "\tEnter the value you want to set :";
    std::cin >> value;

    setAttribute[key] = value;
    resource->setRemoteAttributes(setAttribute,
                                  &onRemoteAttributesReceivedCallback);
}

void startCaching(std::function <void (const RCSResourceAttributes&)>cb)
{
    if (!resource->isCaching())
    {
        if(cb) resource->startCaching(&onCacheUpdated);

        else resource->startCaching();

        std::cout << "\tCaching Started..." << std::endl;
    }
    else
    {
        std::cout << "\tAlready Started Caching..." << std::endl;
    }
}

void startCachingWithoutCallback()
{
    startCaching(nullptr);
}

void startCachingWithCallback()
{
    startCaching(onCacheUpdated);
}

void getResourceCacheState()
{
    switch(resource->getCacheState())
    {
        case CacheState::READY:
            std::cout << "\tCurrent Cache State : " << "CACHE_STATE ::READY" << std::endl;
            break;

        case CacheState::UNREADY:
            std::cout << "\tCurrent Cache State : " << "CACHE_STATE ::UNREADY" << std::endl;
            break;

        case CacheState::LOST_SIGNAL:
            std::cout << "\tCurrent Cache State : " << "CACHE_STATE ::LOST_SIGNAL" << std::endl;
            break;

        case CacheState::NONE:
            std::cout << "\tCurrent Cache State : " << "CACHE_STATE ::NONE" << std::endl;
            break;

        default:
            break;
    }
}

void getCachedAttributes()
{
    try
    {
        if (resource->getCachedAttributes().empty())
        {
            std::cout << "\tReceived cached attribute is empty" << std::endl;
        }
        else
        {
            for(const auto& attr : resource->getCachedAttributes())
            {
                std::cout << "\tkey : " << attr.key() << std::endl
                          << "\tvalue : " << attr.value().toString() << std::endl;
            }
        }
    }
    catch (const BadRequestException& e)
    {
        std::cout << "Exception in getCachedAttributes : " << e.what() << std::endl;
    }
}

void getCachedAttribute()
{
    try
    {
        std::cout << "\tkey : " << defaultKey << std::endl
                  << "\tvalue : " << resource->getCachedAttribute(defaultKey).get< int >()
                  << std::endl;
    }
    catch (const BadRequestException& e)
    {
        std::cout << "Exception in getCachedAttribute : " << e.what() << std::endl;
    }
    catch (const BadGetException& e)
    {
        std::cout << "Exception in getCachedAttribute : " << e.what() << std::endl;
    }
}

void stopCaching()
{
    if(resource->isCaching())
    {
        resource->stopCaching();
        std::cout << "\tCaching stopped..." << std::endl;
    }
    else
    {
        std::cout << "\tCaching not started..." << std::endl;
    }
}

int selectClientMenu(int selectedMenu)
{
    for(int i = 0; clientMenu[i].m_menu != Menu::END_OF_MENU; i++)
    {
        if(clientMenu[i].m_menu == selectedMenu)
        {
            clientMenu[i].m_handler();
            return clientMenu[i].m_result;
        }
    }

    std::cout << "Invalid input, please try again" << std::endl;

    return INCORRECT_INPUT;
}

void process()
{
    while(true)
    {
        displayMenu();

        if(selectClientMenu(processUserInput()) == QUIT_INPUT) break;
    }
}

void platFormConfigure()
{
    PlatformConfig config
    {
        OC::ServiceType::InProc, ModeType::Client, "0.0.0.0", 0, OC::QualityOfService::LowQos
    };
    OCPlatform::Configure(config);
}

void discoverResource()
{
    std::string resourceType;

    std::cout << "========================================================" << std::endl;
    std::cout << "1. Temperature Resource Discovery" << std::endl;
    std::cout << "2. Light Resource Discovery" << std::endl;
    std::cout << "========================================================" << std::endl;

    switch (processUserInput())
    {
    case REQUEST_TEMP:
        resourceType = "core.TemperatureSensor";
        break;
    case REQUEST_LIGHT:
        resourceType = "core.light";
        defaultKey = "Light";
        break;
    default :
        std::cout << "Invalid input, please try again" << std::endl;
        return;
    }

    std::string addressInput;
    std::cout << "========================================================" << std::endl;
    std::cout << "Please input address" << std::endl;
    std::cout << "(want to use multicast -> please input 'multi')" << std::endl;
    std::cout << "========================================================" << std::endl;

    std::cin >> addressInput;

    if(addressInput == multicastAdd)
    {
        discoveryTask = RCSDiscoveryManager::getInstance()->discoverResourceByType(RCSAddress::multicast(),
                relativeUri, resourceType, &onResourceDiscovered);
    }
    else
    {
        discoveryTask = RCSDiscoveryManager::getInstance()->discoverResourceByType(RCSAddress::unicast
                (addressInput), relativeUri, resourceType, &onResourceDiscovered);
    }
}

void cancelDiscovery()
{
    if(!discoveryTask)
    {
        std::cout << "There isn't discovery request..." << std::endl;
        return;
    }
    discoveryTask->cancel();
}

int main()
{
    platFormConfigure();

    try
    {
        process();
    }
    catch (const std::exception& e)
    {
        std::cout << "main exception : " << e.what() << std::endl;
    }

    std::cout << "Stopping the Client" << std::endl;

    return 0;
}
<|endoftext|>