<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/io/p9_io_obus_linktrain.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,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 p9_io_obus_linktrain.C
/// @brief I/O Link Training on the Abus(Obus PHY) Links.
///-----------------------------------------------------------------------------
/// *HWP HWP Owner        : Chris Steffen <cwsteffen@us.ibm.com>
/// *HWP HWP Backup Owner : Gary Peterson <garyp@us.ibm.com>
/// *HWP FW Owner         : Jamie Knight <rjknight@us.ibm.com>
/// *HWP Team             : IO
/// *HWP Level            : 3
/// *HWP Consumed by      : FSP:HB
///-----------------------------------------------------------------------------
///
/// @verbatim
/// High-level procedure flow:
///
/// Train the link.
///
/// Procedure Prereq:
///     - System clocks are running.
///     - Scominit Procedure is completed.
///     - Dccal Procedure is completed.
///
/// @endverbatim
///----------------------------------------------------------------------------

//------------------------------------------------------------------------------
//  Defines
//------------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//  Includes
//-----------------------------------------------------------------------------
#include <p9_io_obus_linktrain.H>
#include <p9_io_scom.H>
#include <p9_io_regs.H>
#include <p9_io_common.H>
#include <p9_obus_scom_addresses.H>
#include <p9_obus_scom_addresses_fld.H>

//-----------------------------------------------------------------------------
//  Definitions
//-----------------------------------------------------------------------------

/**
 * @brief A HWP to perform FIFO init for ABUS(OPT)
 * @param[in] i_mode  Linktraining Mode
 * @param[in] i_tgt   Reference to the Target
 * @retval    ReturnCode
 */
fapi2::ReturnCode p9_io_obus_linktrain(const OBUS_TGT& i_tgt)
{
    FAPI_IMP("p9_io_obus_linktrain: P9 I/O OPT Abus Entering");
    const uint32_t MAX_LANES         = 24;
    const uint8_t  GRP0              = 0;
    char l_tgt_str[fapi2::MAX_ECMD_STRING_LEN];
    fapi2::toString(i_tgt,  l_tgt_str,  fapi2::MAX_ECMD_STRING_LEN);
    fapi2::buffer<uint64_t> l_data = 0;
    fapi2::buffer<uint64_t> l_dl_control_data;
    fapi2::buffer<uint64_t> l_dl_control_mask;
    fapi2::ATTR_PROC_FABRIC_LINK_ACTIVE_Type l_fbc_active;
    fapi2::ATTR_LINK_TRAIN_Type l_link_train;
    fapi2::ATTR_CHIP_EC_FEATURE_HW419022_Type l_hw419022 = 0;
    fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> i_chip_target =
        i_tgt.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();
    bool l_even = true;
    bool l_odd = true;

    FAPI_DBG("I/O Abus FIFO init: Target(%s)", l_tgt_str);

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_LINK_ACTIVE,
                           i_tgt,
                           l_fbc_active),
             "Error from FAPI_ATTR_GET (ATTR_PROC_FABRIC_LINK_ACTIVE)");

    if (!l_fbc_active)
    {
        FAPI_DBG("Skipping link, not active for FBC protocol");
        goto fapi_try_exit;
    }

    // PHY initialization sequence:
    // - clear TX_UNLOAD_CLK_DISABLE
    // - set TX_FIFO_INIT
    // - set TX_UNLOAD_CLK_DISABLE
    // - set RX_AC_COUPLED

    // Clear TX_UNLOAD_CLK_DISABLE
    for (uint32_t lane = 0; lane < MAX_LANES; ++lane)
    {
        FAPI_TRY(io::read(OPT_TX_MODE2_PL, i_tgt, GRP0, lane, l_data));
        io::set(OPT_TX_UNLOAD_CLK_DISABLE, 0, l_data);
        FAPI_TRY(io::write(OPT_TX_MODE2_PL, i_tgt, GRP0, lane, l_data));
    }

    // Set TX_FIFO_INIT
    l_data.flush<0>();
    io::set(OPT_TX_FIFO_INIT, 1, l_data);

    for (uint32_t lane = 0; lane < MAX_LANES; ++lane)
    {
        FAPI_TRY(io::write(OPT_TX_CNTL1G_PL, i_tgt, GRP0, lane, l_data));
    }

    // Set TX_UNLOAD_CLK_DISABLE
    for (uint32_t lane = 0; lane < MAX_LANES; ++lane)
    {
        FAPI_TRY(io::read(OPT_TX_MODE2_PL, i_tgt, GRP0, lane, l_data));
        io::set(OPT_TX_UNLOAD_CLK_DISABLE, 1, l_data );
        FAPI_TRY(io::write(OPT_TX_MODE2_PL, i_tgt, GRP0, lane, l_data));
    }

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_HW419022,
                           i_chip_target,
                           l_hw419022),
             "Error from FAPI_ATTR_GET (fapi2::ATTR_CHIP_EC_FEATURE_HW419022)");

    // Cable CDR lock
    // determine link train capabilities (half/full)
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_LINK_TRAIN,
                           i_tgt,
                           l_link_train),
             "Error from FAPI_ATTR_GET (ATTR_LINK_TRAIN)");

    l_even = (l_link_train == fapi2::ENUM_ATTR_LINK_TRAIN_BOTH) ||
             (l_link_train == fapi2::ENUM_ATTR_LINK_TRAIN_EVEN_ONLY);

    l_odd = (l_link_train == fapi2::ENUM_ATTR_LINK_TRAIN_BOTH) ||
            (l_link_train == fapi2::ENUM_ATTR_LINK_TRAIN_ODD_ONLY);

    // set TX lane control to force send of TS1 pattern
    if (l_even)
    {
        FAPI_TRY(fapi2::putScom(i_tgt,
                                OBUS_LL0_IOOL_LINK0_TX_LANE_CONTROL,
                                0x1111111111100000ULL),
                 "Error from putScom (OBUS_LL0_IOOL_LINK0_TX_LANE_CONTROL)");
    }

    if (l_odd)
    {
        FAPI_TRY(fapi2::putScom(i_tgt,
                                OBUS_LL0_IOOL_LINK1_TX_LANE_CONTROL,
                                0x1111111111100000ULL),
                 "Error from putScom (OBUS_LL0_IOOL_LINK1_TX_LANE_CONTROL)");
    }

    // Delay to compensate for active links
    FAPI_TRY(fapi2::delay(100000000, 1000000),
             "Error from A-link retimer delay");

    // DD1.1+ HW Start training sequence
    if(!l_hw419022)
    {
        // clear TX lane control overrides
        if (l_even)
        {
            l_dl_control_data.setBit<OBUS_LL0_IOOL_CONTROL_LINK0_PHY_TRAINING>();
            l_dl_control_mask.setBit<OBUS_LL0_IOOL_CONTROL_LINK0_PHY_TRAINING>();

            FAPI_TRY(fapi2::putScom(i_tgt,
                                    OBUS_LL0_IOOL_LINK0_TX_LANE_CONTROL,
                                    0x0000000000000000ULL),
                     "Error from putScom (OBUS_LL0_IOOL_LINK0_TX_LANE_CONTROL)");
        }

        if (l_odd)
        {
            l_dl_control_data.setBit<OBUS_LL0_IOOL_CONTROL_LINK1_PHY_TRAINING>();
            l_dl_control_mask.setBit<OBUS_LL0_IOOL_CONTROL_LINK1_PHY_TRAINING>();

            FAPI_TRY(fapi2::putScom(i_tgt,
                                    OBUS_LL0_IOOL_LINK1_TX_LANE_CONTROL,
                                    0x0000000000000000ULL),
                     "Error from putScom (OBUS_LL0_IOOL_LINK1_TX_LANE_CONTROL)");
        }

        // Start phy training
        FAPI_TRY(fapi2::putScomUnderMask(i_tgt,
                                         OBUS_LL0_IOOL_CONTROL,
                                         l_dl_control_data,
                                         l_dl_control_mask),
                 "Error writing DLL control register (0x%08X)!",
                 OBUS_LL0_IOOL_CONTROL);
    }

fapi_try_exit:
    FAPI_IMP("p9_io_obus_linktrain: P9 I/O OPT Abus Exiting");
    return fapi2::current_err;
}
<commit_msg>SMP Abus PPE Workaround<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/io/p9_io_obus_linktrain.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,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 p9_io_obus_linktrain.C
/// @brief I/O Link Training on the Abus(Obus PHY) Links.
///-----------------------------------------------------------------------------
/// *HWP HWP Owner        : Chris Steffen <cwsteffen@us.ibm.com>
/// *HWP HWP Backup Owner : Gary Peterson <garyp@us.ibm.com>
/// *HWP FW Owner         : Jamie Knight <rjknight@us.ibm.com>
/// *HWP Team             : IO
/// *HWP Level            : 3
/// *HWP Consumed by      : FSP:HB
///-----------------------------------------------------------------------------
///
/// @verbatim
/// High-level procedure flow:
///
/// Train the link.
///
/// Procedure Prereq:
///     - System clocks are running.
///     - Scominit Procedure is completed.
///     - Dccal Procedure is completed.
///
/// @endverbatim
///----------------------------------------------------------------------------

//------------------------------------------------------------------------------
//  Defines
//------------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//  Includes
//-----------------------------------------------------------------------------
#include <p9_io_obus_linktrain.H>
#include <p9_io_obus_pdwn_lanes.H>
#include <p9_io_scom.H>
#include <p9_io_regs.H>
#include <p9_io_common.H>
#include <p9_obus_scom_addresses.H>
#include <p9_obus_scom_addresses_fld.H>

//-----------------------------------------------------------------------------
//  Definitions
//-----------------------------------------------------------------------------

/**
 * @brief A HWP to perform FIFO init for ABUS(OPT)
 * @param[in] i_mode  Linktraining Mode
 * @param[in] i_tgt   Reference to the Target
 * @retval    ReturnCode
 */
fapi2::ReturnCode p9_io_obus_linktrain(const OBUS_TGT& i_tgt)
{
    FAPI_IMP("p9_io_obus_linktrain: P9 I/O OPT Abus Entering");
    const uint32_t MAX_LANES         = 24;
    const uint8_t  GRP0              = 0;
    char l_tgt_str[fapi2::MAX_ECMD_STRING_LEN];
    fapi2::toString(i_tgt,  l_tgt_str,  fapi2::MAX_ECMD_STRING_LEN);
    fapi2::buffer<uint64_t> l_data = 0;
    fapi2::buffer<uint64_t> l_dl_control_data;
    fapi2::buffer<uint64_t> l_dl_control_mask;
    fapi2::ATTR_PROC_FABRIC_LINK_ACTIVE_Type l_fbc_active;
    fapi2::ATTR_LINK_TRAIN_Type l_link_train;
    fapi2::ATTR_CHIP_EC_FEATURE_HW419022_Type l_hw419022 = 0;
    fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> i_chip_target =
        i_tgt.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();
    bool l_even = true;
    bool l_odd = true;

    FAPI_DBG("I/O Abus FIFO init: Target(%s)", l_tgt_str);

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_PROC_FABRIC_LINK_ACTIVE,
                           i_tgt,
                           l_fbc_active),
             "Error from FAPI_ATTR_GET (ATTR_PROC_FABRIC_LINK_ACTIVE)");

    if (!l_fbc_active)
    {
        FAPI_DBG("Skipping link, not active for FBC protocol");
        goto fapi_try_exit;
    }

    // PHY initialization sequence:
    // - clear TX_UNLOAD_CLK_DISABLE
    // - set TX_FIFO_INIT
    // - set TX_UNLOAD_CLK_DISABLE
    // - set RX_AC_COUPLED

    // Clear TX_UNLOAD_CLK_DISABLE
    for (uint32_t lane = 0; lane < MAX_LANES; ++lane)
    {
        FAPI_TRY(io::read(OPT_TX_MODE2_PL, i_tgt, GRP0, lane, l_data));
        io::set(OPT_TX_UNLOAD_CLK_DISABLE, 0, l_data);
        FAPI_TRY(io::write(OPT_TX_MODE2_PL, i_tgt, GRP0, lane, l_data));
    }

    // Set TX_FIFO_INIT
    l_data.flush<0>();
    io::set(OPT_TX_FIFO_INIT, 1, l_data);

    for (uint32_t lane = 0; lane < MAX_LANES; ++lane)
    {
        FAPI_TRY(io::write(OPT_TX_CNTL1G_PL, i_tgt, GRP0, lane, l_data));
    }

    // Set TX_UNLOAD_CLK_DISABLE
    for (uint32_t lane = 0; lane < MAX_LANES; ++lane)
    {
        FAPI_TRY(io::read(OPT_TX_MODE2_PL, i_tgt, GRP0, lane, l_data));
        io::set(OPT_TX_UNLOAD_CLK_DISABLE, 1, l_data );
        FAPI_TRY(io::write(OPT_TX_MODE2_PL, i_tgt, GRP0, lane, l_data));
    }

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_HW419022,
                           i_chip_target,
                           l_hw419022),
             "Error from FAPI_ATTR_GET (fapi2::ATTR_CHIP_EC_FEATURE_HW419022)");

    // Cable CDR lock
    // determine link train capabilities (half/full)
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_LINK_TRAIN,
                           i_tgt,
                           l_link_train),
             "Error from FAPI_ATTR_GET (ATTR_LINK_TRAIN)");

    l_even = (l_link_train == fapi2::ENUM_ATTR_LINK_TRAIN_BOTH) ||
             (l_link_train == fapi2::ENUM_ATTR_LINK_TRAIN_EVEN_ONLY);

    l_odd = (l_link_train == fapi2::ENUM_ATTR_LINK_TRAIN_BOTH) ||
            (l_link_train == fapi2::ENUM_ATTR_LINK_TRAIN_ODD_ONLY);

    // set TX lane control to force send of TS1 pattern
    if (l_even)
    {
        FAPI_TRY(fapi2::putScom(i_tgt,
                                OBUS_LL0_IOOL_LINK0_TX_LANE_CONTROL,
                                0x1111111111100000ULL),
                 "Error from putScom (OBUS_LL0_IOOL_LINK0_TX_LANE_CONTROL)");
    }
    else
    {
        const uint32_t EVEN_LANES = 0x000007FF;
        FAPI_TRY(p9_io_obus_pdwn_lanes(i_tgt, EVEN_LANES),
                 "Error from p9_io_obus_pdwn_lanes");
    }

    if (l_odd)
    {
        FAPI_TRY(fapi2::putScom(i_tgt,
                                OBUS_LL0_IOOL_LINK1_TX_LANE_CONTROL,
                                0x1111111111100000ULL),
                 "Error from putScom (OBUS_LL0_IOOL_LINK1_TX_LANE_CONTROL)");
    }
    else
    {
        const uint32_t ODD_LANES = 0x00FFE000;
        FAPI_TRY(p9_io_obus_pdwn_lanes(i_tgt, ODD_LANES),
                 "Error from p9_io_obus_pdwn_lanes");
    }

    // Delay to compensate for active links
    FAPI_TRY(fapi2::delay(100000000, 1000000),
             "Error from A-link retimer delay");

    // DD1.1+ HW Start training sequence
    if(!l_hw419022)
    {
        // clear TX lane control overrides
        if (l_even)
        {
            l_dl_control_data.setBit<OBUS_LL0_IOOL_CONTROL_LINK0_PHY_TRAINING>();
            l_dl_control_mask.setBit<OBUS_LL0_IOOL_CONTROL_LINK0_PHY_TRAINING>();

            FAPI_TRY(fapi2::putScom(i_tgt,
                                    OBUS_LL0_IOOL_LINK0_TX_LANE_CONTROL,
                                    0x0000000000000000ULL),
                     "Error from putScom (OBUS_LL0_IOOL_LINK0_TX_LANE_CONTROL)");
        }

        if (l_odd)
        {
            l_dl_control_data.setBit<OBUS_LL0_IOOL_CONTROL_LINK1_PHY_TRAINING>();
            l_dl_control_mask.setBit<OBUS_LL0_IOOL_CONTROL_LINK1_PHY_TRAINING>();

            FAPI_TRY(fapi2::putScom(i_tgt,
                                    OBUS_LL0_IOOL_LINK1_TX_LANE_CONTROL,
                                    0x0000000000000000ULL),
                     "Error from putScom (OBUS_LL0_IOOL_LINK1_TX_LANE_CONTROL)");
        }

        // Start phy training
        FAPI_TRY(fapi2::putScomUnderMask(i_tgt,
                                         OBUS_LL0_IOOL_CONTROL,
                                         l_dl_control_data,
                                         l_dl_control_mask),
                 "Error writing DLL control register (0x%08X)!",
                 OBUS_LL0_IOOL_CONTROL);
    }

fapi_try_exit:
    FAPI_IMP("p9_io_obus_linktrain: P9 I/O OPT Abus Exiting");
    return fapi2::current_err;
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_block_wakeup_intr.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,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 p9_block_wakeup_intr.C
/// @brief Set/reset the BLOCK_REG_WKUP_SOURCES bit in the PCBS-PM associated
///          with an EX chiplet
///
//  *HWP HWP Owner: Amit Kumar <akumar3@us.ibm.com>
//  *HWP FW Owner: Bilicon Patil <bilpatil@in.ibm.com>
//  *HWP Team: PM
//  *HWP Level: 2
//  *HWP Consumed by: FSP:HS
///
/// @verbatim
/// High-level procedure flow:
///
///   With set/reset enum parameter, either set or clear PMGP0(53)
///
/// Procedure Prereq:
///    - System clocks are running
/// @endverbatim
///
//------------------------------------------------------------------------------

// ----------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------

#include <p9_block_wakeup_intr.H>

// This must stay in sync with enum OP_TYPE enum in header file
const char* OP_TYPE_STRING[] =
{
    "SET",
    "CLEAR"
};

// ----------------------------------------------------------------------
// Procedure Function
// ----------------------------------------------------------------------

/// @brief @brief Set/reset the BLOCK_INTR_INPUTS bit in the Core PPM
///         associated with an EX chiplet

fapi2::ReturnCode
p9_block_wakeup_intr(
    const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_core_target,
    const p9pmblockwkup::OP_TYPE i_operation)
{
    FAPI_INF("> p9_block_wakeup_intr...");

    fapi2::buffer<uint64_t> l_data64 = 0;

    // Get the core number
    uint8_t l_attr_chip_unit_pos = 0;
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                           i_core_target,
                           l_attr_chip_unit_pos),
             "fapiGetAttribute of ATTR_CHIP_UNIT_POS failed");

    // Read for trace
    {
        fapi2::buffer<uint64_t> l_cpmmr = 0;
        fapi2::buffer<uint64_t> l_gpmmr = 0;

        // Read the CPMMR and GPMMR as a trace
        FAPI_TRY(fapi2::getScom(i_core_target,
                                C_CPPM_CPMMR,
                                l_cpmmr),
                 "getScom of CPMMR failed");

        FAPI_TRY(fapi2::getScom(i_core_target,
                                C_PPM_GPMMR,
                                l_gpmmr),
                 "getScom of GPMMR failed");

        FAPI_DBG("Debug: before setting PPM_WRITE_OVERRIDE on Core %d - CPPMR: 0x%016llX GPMMR: 0x%016llX",
                 l_attr_chip_unit_pos, l_cpmmr, l_gpmmr);
    }

    // Ensure access to the GPMMR is in place using CPMMR Write Access
    // Override.  This will not affect the CME functionality as only the
    // Block Wake-up bit is being manipulated -- a bit that the CME does
    // not control but does react upon.

    FAPI_INF("Set the CPPM PPM Write Override");
    l_data64.flush<0>().setBit<C_CPPM_CPMMR_PPM_WRITE_OVERRIDE>();
    FAPI_TRY(fapi2::putScom(i_core_target,
                            C_CPPM_CPMMR_OR,
                            l_data64),
             "putScom of CPMMR to set PMM Write Override failed");

    l_data64.flush<0>().setBit<BLOCK_REG_WKUP_EVENTS>();

    switch (i_operation)
    {
        case p9pmblockwkup::SET:

            // @todo RTC 144905 Add Special Wakeup setting here when available

            FAPI_INF("Setting GPMMR[Block Interrupt Sources] on Core %d",
                     l_attr_chip_unit_pos);

            FAPI_TRY(fapi2::putScom(i_core_target,
                                    C_PPM_GPMMR_OR,
                                    l_data64),
                     "Setting GPMMR failed");

            // @todo RTC 144905 Add Special Wakeup clearing here when available

            break;

        case p9pmblockwkup::SET_NOSPWUP:
            FAPI_INF("Setting GPMMR[Block Interrupt Sources] without Special Wake-up on Core %d",
                     l_attr_chip_unit_pos);

            FAPI_TRY(fapi2::putScom(i_core_target,
                                    C_PPM_GPMMR_OR,
                                    l_data64),
                     "Setting GPMMR failed");
            break;

        case p9pmblockwkup::CLEAR:
            FAPI_INF("Clearing GPMMR[Block Interrupt Sources] on Core %d",
                     l_attr_chip_unit_pos);

            FAPI_TRY(fapi2::putScom(i_core_target,
                                    C_PPM_GPMMR_CLEAR,
                                    l_data64),
                     "Clearing GPMMR failed");
            break;

        default:
            ;
    }

    FAPI_INF("Clear the CPPM PPM Write Override");
    l_data64.flush<0>().setBit<C_CPPM_CPMMR_PPM_WRITE_OVERRIDE>();
    FAPI_TRY(fapi2::putScom(i_core_target,
                            C_CPPM_CPMMR_CLEAR,
                            l_data64),
             "putScom of CPMMR to clear PMM Write Override failed");

fapi_try_exit:
    FAPI_INF("< p9_block_wakeup_intr...");
    return fapi2::current_err;
}
<commit_msg>p9_block_wakeup_intr Level 2 - fix PPE compilation issue<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_block_wakeup_intr.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,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 p9_block_wakeup_intr.C
/// @brief Set/reset the BLOCK_REG_WKUP_SOURCES bit in the PCBS-PM associated
///          with an EX chiplet
///
//  *HWP HWP Owner: Amit Kumar <akumar3@us.ibm.com>
//  *HWP FW Owner: Prem Jha <premjha1@in.ibm.com>
//  *HWP Team: PM
//  *HWP Level: 2
//  *HWP Consumed by: FSP:HS
///
/// @verbatim
/// High-level procedure flow:
///
///   With set/reset enum parameter, either set or clear PMGP0(53)
///
/// Procedure Prereq:
///    - System clocks are running
/// @endverbatim
///
//------------------------------------------------------------------------------

// ----------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------

#include <p9_block_wakeup_intr.H>
#include <p9_hcd_common.H>

// This must stay in sync with enum OP_TYPE enum in header file
const char* OP_TYPE_STRING[] =
{
    "SET",
    "CLEAR"
};

// ----------------------------------------------------------------------
// Procedure Function
// ----------------------------------------------------------------------

/// @brief @brief Set/reset the BLOCK_INTR_INPUTS bit in the Core PPM
///         associated with an EX chiplet

fapi2::ReturnCode
p9_block_wakeup_intr(
    const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_core_target,
    const p9pmblockwkup::OP_TYPE i_operation)
{
    FAPI_INF("> p9_block_wakeup_intr...");

    fapi2::buffer<uint64_t> l_data64 = 0;

    // Get the core number
    uint8_t l_attr_chip_unit_pos = 0;

    fapi2::Target<fapi2::TARGET_TYPE_PERV> l_perv =
        i_core_target.getParent<fapi2::TARGET_TYPE_PERV>();

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                           l_perv,
                           l_attr_chip_unit_pos),
             "fapiGetAttribute of ATTR_CHIP_UNIT_POS failed");
    l_attr_chip_unit_pos = l_attr_chip_unit_pos - p9hcd::PERV_TO_CORE_POS_OFFSET;

    // Read for trace
    {
        fapi2::buffer<uint64_t> l_cpmmr = 0;
        fapi2::buffer<uint64_t> l_gpmmr = 0;

        // Read the CPMMR and GPMMR as a trace
        FAPI_TRY(fapi2::getScom(i_core_target,
                                C_CPPM_CPMMR,
                                l_cpmmr),
                 "getScom of CPMMR failed");

        FAPI_TRY(fapi2::getScom(i_core_target,
                                C_PPM_GPMMR,
                                l_gpmmr),
                 "getScom of GPMMR failed");

        FAPI_DBG("Debug: before setting PPM_WRITE_OVERRIDE on Core %d - CPPMR: 0x%016llX GPMMR: 0x%016llX",
                 l_attr_chip_unit_pos, l_cpmmr, l_gpmmr);
    }

    // Ensure access to the GPMMR is in place using CPMMR Write Access
    // Override.  This will not affect the CME functionality as only the
    // Block Wake-up bit is being manipulated -- a bit that the CME does
    // not control but does react upon.

    FAPI_INF("Set the CPPM PPM Write Override");
    l_data64.flush<0>().setBit<C_CPPM_CPMMR_PPM_WRITE_OVERRIDE>();
    FAPI_TRY(fapi2::putScom(i_core_target,
                            C_CPPM_CPMMR_OR,
                            l_data64),
             "putScom of CPMMR to set PMM Write Override failed");

    l_data64.flush<0>().setBit<BLOCK_REG_WKUP_EVENTS>();

    switch (i_operation)
    {
        case p9pmblockwkup::SET:

            // @todo RTC 144905 Add Special Wakeup setting here when available

            FAPI_INF("Setting GPMMR[Block Interrupt Sources] on Core %d",
                     l_attr_chip_unit_pos);

            FAPI_TRY(fapi2::putScom(i_core_target,
                                    C_PPM_GPMMR_OR,
                                    l_data64),
                     "Setting GPMMR failed");

            // @todo RTC 144905 Add Special Wakeup clearing here when available

            break;

        case p9pmblockwkup::SET_NOSPWUP:
            FAPI_INF("Setting GPMMR[Block Interrupt Sources] without Special Wake-up on Core %d",
                     l_attr_chip_unit_pos);

            FAPI_TRY(fapi2::putScom(i_core_target,
                                    C_PPM_GPMMR_OR,
                                    l_data64),
                     "Setting GPMMR failed");
            break;

        case p9pmblockwkup::CLEAR:
            FAPI_INF("Clearing GPMMR[Block Interrupt Sources] on Core %d",
                     l_attr_chip_unit_pos);

            FAPI_TRY(fapi2::putScom(i_core_target,
                                    C_PPM_GPMMR_CLEAR,
                                    l_data64),
                     "Clearing GPMMR failed");
            break;

        default:
            ;
    }

    FAPI_INF("Clear the CPPM PPM Write Override");
    l_data64.flush<0>().setBit<C_CPPM_CPMMR_PPM_WRITE_OVERRIDE>();
    FAPI_TRY(fapi2::putScom(i_core_target,
                            C_CPPM_CPMMR_CLEAR,
                            l_data64),
             "putScom of CPMMR to clear PMM Write Override failed");

fapi_try_exit:
    FAPI_INF("< p9_block_wakeup_intr...");
    return fapi2::current_err;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: helpagentwindow.cxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: fs $ $Date: 2001-05-07 15:18:58 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SVTOOLS_HELPAGENTWIDNOW_HXX_
#include "helpagentwindow.hxx"
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef _SV_BITMAP_HXX
#include <vcl/bitmap.hxx>
#endif
#ifndef _SVTOOLS_HRC
#include "svtools.hrc"
#endif
#ifndef _SVTOOLS_SVTDATA_HXX
#include <svtools/svtdata.hxx>
#endif

#define WB_AGENT_STYLE  0

//........................................................................
namespace svt
{
//........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::awt;
    using namespace ::com::sun::star::lang;

    //====================================================================
    //= HelpAgentWindow
    //====================================================================
    //--------------------------------------------------------------------
    HelpAgentWindow::HelpAgentWindow( Window* _pParent )
        :FloatingWindow( _pParent, WB_AGENT_STYLE)
        ,m_pCloser(NULL)
        ,m_pCallback(NULL)
    {
        // -----------------
        // the closer button
        Bitmap aCloserBitmap(SvtResId(BMP_HELP_AGENT_CLOSER));
        Image aCloserImage( aCloserBitmap );
        m_pCloser = new ImageButton( this, WB_NOTABSTOP | WB_NOPOINTERFOCUS );
        static_cast<ImageButton*>(m_pCloser)->SetImage( aCloserImage );
        static_cast<ImageButton*>(m_pCloser)->SetClickHdl( LINK(this, HelpAgentWindow, OnButtonClicked) );
        m_pCloser->SetSizePixel( implOptimalButtonSize(aCloserImage) );
        m_pCloser->Show();
        m_pCloser->SetZOrder( NULL, WINDOW_ZORDER_LAST );

        // ----------------------------
        // calculate our preferred size
        Bitmap aHelpAgentBitmap(SvtResId(BMP_HELP_AGENT_IMAGE));
        m_aPicture = Image( aHelpAgentBitmap );
        m_aPreferredSize = m_aPicture.GetSizePixel();
        m_aPreferredSize.Width() += 2;
        m_aPreferredSize.Height() += 2;

        Size aSize = GetSizePixel();
        Size aOutputSize = GetOutputSizePixel();
        m_aPreferredSize.Width() += aSize.Width() - aOutputSize.Width();
        m_aPreferredSize.Height() += aSize.Height() - aOutputSize.Height();

        SetPointer(Pointer(POINTER_REFHAND));
    }

    //--------------------------------------------------------------------
    HelpAgentWindow::~HelpAgentWindow()
    {
        if (m_pCloser && m_pCloser->IsTracking())
            m_pCloser->EndTracking();
        if (m_pCloser && m_pCloser->IsMouseCaptured())
            m_pCloser->ReleaseMouse();

        delete m_pCloser;
    }

    //--------------------------------------------------------------------
    void HelpAgentWindow::Paint( const Rectangle& rRect )
    {
        FloatingWindow::Paint(rRect);

        Size        aOutputSize( GetOutputSizePixel() );
        Rectangle   aOutputRect( Point(), aOutputSize );
        Rectangle   aInnerRect( aOutputRect );

        // paint the background
        SetLineColor( GetSettings().GetStyleSettings().GetFaceColor() );
        SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() );
        DrawRect( aOutputRect );

        // paint the image
        Size aPictureSize( m_aPicture.GetSizePixel() );
        Point aPicturePos(
            aOutputRect.Left() + (aInnerRect.GetWidth() - aPictureSize.Width()) / 2,
            aOutputRect.Top() + (aInnerRect.GetHeight() - aPictureSize.Height()) / 2 );

        DrawImage( aPicturePos, m_aPicture, 0 );
    }

    //--------------------------------------------------------------------
    void HelpAgentWindow::MouseButtonUp( const MouseEvent& rMEvt )
    {
        FloatingWindow::MouseButtonUp(rMEvt);

        if (m_pCallback)
            m_pCallback->helpRequested();
    }

    //--------------------------------------------------------------------
    Size HelpAgentWindow::implOptimalButtonSize( const Image& _rButtonImage )
    {
        Size aPreferredSize = _rButtonImage.GetSizePixel();
        // add a small frame, needed by the button
        aPreferredSize.Width() += 5;
        aPreferredSize.Height() += 5;
        return aPreferredSize;
    }

    //--------------------------------------------------------------------
    void HelpAgentWindow::Resize()
    {
        FloatingWindow::Resize();

        Size aOutputSize = GetOutputSizePixel();
        Size aCloserSize = m_pCloser->GetSizePixel();
        if (m_pCloser)
            m_pCloser->SetPosPixel( Point(aOutputSize.Width() - aCloserSize.Width() - 3, 4) );
    }

    //--------------------------------------------------------------------
    IMPL_LINK( HelpAgentWindow, OnButtonClicked, Window*, _pWhichOne )
    {
        if (m_pCloser == _pWhichOne)
            if (m_pCallback)
                m_pCallback->closeAgent();
        return 0L;
    }

//........................................................................
}   // namespace svt
//........................................................................

/*************************************************************************
 * history:
 *  $Log: not supported by cvs2svn $
 *  Revision 1.1  2001/05/07 13:42:30  fs
 *  initial checkin - help agent window
 *
 *
 *  Revision 1.0 03.05.01 11:51:40  fs
 ************************************************************************/

<commit_msg>#65293# fix for gcc (needs temporary variable for Point() )<commit_after>/*************************************************************************
 *
 *  $RCSfile: helpagentwindow.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2001-05-11 09:07:24 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _SVTOOLS_HELPAGENTWIDNOW_HXX_
#include "helpagentwindow.hxx"
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef _SV_BITMAP_HXX
#include <vcl/bitmap.hxx>
#endif
#ifndef _SVTOOLS_HRC
#include "svtools.hrc"
#endif
#ifndef _SVTOOLS_SVTDATA_HXX
#include <svtools/svtdata.hxx>
#endif

#define WB_AGENT_STYLE  0

//........................................................................
namespace svt
{
//........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::awt;
    using namespace ::com::sun::star::lang;

    //====================================================================
    //= HelpAgentWindow
    //====================================================================
    //--------------------------------------------------------------------
    HelpAgentWindow::HelpAgentWindow( Window* _pParent )
        :FloatingWindow( _pParent, WB_AGENT_STYLE)
        ,m_pCloser(NULL)
        ,m_pCallback(NULL)
    {
        // -----------------
        // the closer button
        Bitmap aCloserBitmap(SvtResId(BMP_HELP_AGENT_CLOSER));
        Image aCloserImage( aCloserBitmap );
        m_pCloser = new ImageButton( this, WB_NOTABSTOP | WB_NOPOINTERFOCUS );
        static_cast<ImageButton*>(m_pCloser)->SetImage( aCloserImage );
        static_cast<ImageButton*>(m_pCloser)->SetClickHdl( LINK(this, HelpAgentWindow, OnButtonClicked) );
        m_pCloser->SetSizePixel( implOptimalButtonSize(aCloserImage) );
        m_pCloser->Show();
        m_pCloser->SetZOrder( NULL, WINDOW_ZORDER_LAST );

        // ----------------------------
        // calculate our preferred size
        Bitmap aHelpAgentBitmap(SvtResId(BMP_HELP_AGENT_IMAGE));
        m_aPicture = Image( aHelpAgentBitmap );
        m_aPreferredSize = m_aPicture.GetSizePixel();
        m_aPreferredSize.Width() += 2;
        m_aPreferredSize.Height() += 2;

        Size aSize = GetSizePixel();
        Size aOutputSize = GetOutputSizePixel();
        m_aPreferredSize.Width() += aSize.Width() - aOutputSize.Width();
        m_aPreferredSize.Height() += aSize.Height() - aOutputSize.Height();

        SetPointer(Pointer(POINTER_REFHAND));
    }

    //--------------------------------------------------------------------
    HelpAgentWindow::~HelpAgentWindow()
    {
        if (m_pCloser && m_pCloser->IsTracking())
            m_pCloser->EndTracking();
        if (m_pCloser && m_pCloser->IsMouseCaptured())
            m_pCloser->ReleaseMouse();

        delete m_pCloser;
    }

    //--------------------------------------------------------------------
    void HelpAgentWindow::Paint( const Rectangle& rRect )
    {
        FloatingWindow::Paint(rRect);

        Size        aOutputSize( GetOutputSizePixel() );
        Point       aPoint=Point();
        Rectangle   aOutputRect( aPoint, aOutputSize );
        Rectangle   aInnerRect( aOutputRect );

        // paint the background
        SetLineColor( GetSettings().GetStyleSettings().GetFaceColor() );
        SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() );
        DrawRect( aOutputRect );

        // paint the image
        Size aPictureSize( m_aPicture.GetSizePixel() );
        Point aPicturePos(
            aOutputRect.Left() + (aInnerRect.GetWidth() - aPictureSize.Width()) / 2,
            aOutputRect.Top() + (aInnerRect.GetHeight() - aPictureSize.Height()) / 2 );

        DrawImage( aPicturePos, m_aPicture, 0 );
    }

    //--------------------------------------------------------------------
    void HelpAgentWindow::MouseButtonUp( const MouseEvent& rMEvt )
    {
        FloatingWindow::MouseButtonUp(rMEvt);

        if (m_pCallback)
            m_pCallback->helpRequested();
    }

    //--------------------------------------------------------------------
    Size HelpAgentWindow::implOptimalButtonSize( const Image& _rButtonImage )
    {
        Size aPreferredSize = _rButtonImage.GetSizePixel();
        // add a small frame, needed by the button
        aPreferredSize.Width() += 5;
        aPreferredSize.Height() += 5;
        return aPreferredSize;
    }

    //--------------------------------------------------------------------
    void HelpAgentWindow::Resize()
    {
        FloatingWindow::Resize();

        Size aOutputSize = GetOutputSizePixel();
        Size aCloserSize = m_pCloser->GetSizePixel();
        if (m_pCloser)
            m_pCloser->SetPosPixel( Point(aOutputSize.Width() - aCloserSize.Width() - 3, 4) );
    }

    //--------------------------------------------------------------------
    IMPL_LINK( HelpAgentWindow, OnButtonClicked, Window*, _pWhichOne )
    {
        if (m_pCloser == _pWhichOne)
            if (m_pCallback)
                m_pCallback->closeAgent();
        return 0L;
    }

//........................................................................
}   // namespace svt
//........................................................................

/*************************************************************************
 * history:
 *  $Log: not supported by cvs2svn $
 *  Revision 1.1  2001/05/07 15:18:58  fs
 *  initial checkin - window for the new help agent
 *
 *  Revision 1.1  2001/05/07 13:42:30  fs
 *  initial checkin - help agent window
 *
 *
 *  Revision 1.0 03.05.01 11:51:40  fs
 ************************************************************************/

<|endoftext|>


<commit_before>// Author: Enric Tejedor CERN  04/2019
// Original PyROOT code by Wim Lavrijsen, LBL

/*************************************************************************
 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

// Bindings
#include "Python.h"
#include "CPyCppyy.h"
#include "RPyROOTApplication.h"

// ROOT
#include "TInterpreter.h"
#include "TSystem.h"
#include "TBenchmark.h"
#include "TStyle.h"
#include "TError.h"
#include "Getline.h"
#include "TVirtualMutex.h"

////////////////////////////////////////////////////////////////////////////
/// \brief Create an RPyROOTApplication.
/// \param[in] ignoreCmdLineOpts True if Python command line options should
///            be ignored.
/// \return false if gApplication is not null, true otherwise.
///
/// If ignoreCmdLineOpts is false, this method processes the command line
/// arguments from sys.argv. A distinction between arguments for
/// TApplication and user arguments can be made by using "-" or "--" as a
/// separator on the command line.
///
/// For example, to enable batch mode from the command line:
/// > python script_name.py -b -- user_arg1 ... user_argn
/// or, if the user script receives no arguments:
/// > python script_name.py -b
bool PyROOT::RPyROOTApplication::CreateApplication(int ignoreCmdLineOpts)
{
   if (!gApplication) {
      int argc = 1;
      char **argv = nullptr;

      if (ignoreCmdLineOpts) {
         argv = new char *[argc];
      } else {
         // Retrieve sys.argv list from Python
         PyObject *argl = PySys_GetObject(const_cast<char *>("argv"));

         if (argl && 0 < PyList_Size(argl))
            argc = (int)PyList_GET_SIZE(argl);

         argv = new char *[argc];
         for (int i = 1; i < argc; ++i) {
            char *argi = const_cast<char *>(CPyCppyy_PyText_AsString(PyList_GET_ITEM(argl, i)));
            if (strcmp(argi, "-") == 0 || strcmp(argi, "--") == 0) {
               // Stop collecting options, the remaining are for the Python script
               argc = i; // includes program name
               break;
            }
            argv[i] = argi;
         }
      }

#if PY_VERSION_HEX < 0x03000000
      if (Py_GetProgramName() && strlen(Py_GetProgramName()) != 0)
         argv[0] = Py_GetProgramName();
      else
         argv[0] = (char *)"python";
#else
      argv[0] = (char *)"python";
#endif

      gApplication = new RPyROOTApplication("PyROOT", &argc, argv);
      delete[] argv; // TApplication ctor has copied argv, so done with it

      return true;
   }

   return false;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Setup the basic ROOT globals gBenchmark, gStyle and gProgname,
/// if not already set.
void PyROOT::RPyROOTApplication::InitROOTGlobals()
{
   if (!gBenchmark)
      gBenchmark = new TBenchmark();
   if (!gStyle)
      gStyle = new TStyle();

   if (!gProgName) // should have been set by TApplication
#if PY_VERSION_HEX < 0x03000000
      gSystem->SetProgname(Py_GetProgramName());
#else
      gSystem->SetProgname("python");
#endif
}

////////////////////////////////////////////////////////////////////////////
/// \brief Translate ROOT error/warning to Python.
static void ErrMsgHandler(int level, Bool_t abort, const char *location, const char *msg)
{
   // Initialization from gEnv (the default handler will return w/o msg b/c level too low)
   if (gErrorIgnoreLevel == kUnset)
      ::DefaultErrorHandler(kUnset - 1, kFALSE, "", "");

   if (level < gErrorIgnoreLevel)
      return;

   // Turn warnings into Python warnings
   if (level >= kError) {
      ::DefaultErrorHandler(level, abort, location, msg);
   } else if (level >= kWarning) {
      static const char *emptyString = "";
      if (!location)
         location = emptyString;
      // This warning might be triggered while holding the ROOT lock, while
      // some other thread is holding the GIL and waiting for the ROOT lock.
      // That will trigger a deadlock.
      // So if ROOT is in MT mode, use ROOT's error handler that doesn't take
      // the GIL.
      if (!gGlobalMutex) {
         // Either printout or raise exception, depending on user settings
         PyErr_WarnExplicit(NULL, (char *)msg, (char *)location, 0, (char *)"ROOT", NULL);
      } else {
         ::DefaultErrorHandler(level, abort, location, msg);
      }
   } else {
      ::DefaultErrorHandler(level, abort, location, msg);
   }
}

////////////////////////////////////////////////////////////////////////////
/// \brief Install the ROOT message handler which will turn ROOT error
/// messages into Python exceptions.
void PyROOT::RPyROOTApplication::InitROOTMessageCallback()
{
   SetErrorHandler((ErrorHandlerFunc_t)&ErrMsgHandler);
}

////////////////////////////////////////////////////////////////////////////
/// \brief Initialize an RPyROOTApplication.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Command line options
PyObject *PyROOT::RPyROOTApplication::InitApplication(PyObject * /*self*/, PyObject *args)
{
   int argc = PyTuple_GET_SIZE(args);
   if (argc == 1) {
      PyObject *ignoreCmdLineOpts = PyTuple_GetItem(args, 0);

      if (!PyBool_Check(ignoreCmdLineOpts)) {
         PyErr_SetString(PyExc_TypeError, "Expected boolean type as argument.");
         return nullptr;
      }

      if (CreateApplication(PyObject_IsTrue(ignoreCmdLineOpts))) {
         InitROOTGlobals();
         InitROOTMessageCallback();
      }
   } else {
      PyErr_Format(PyExc_TypeError, "Expected 1 argument, %d passed.", argc);
      return nullptr;
   }

   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Construct a TApplication for PyROOT.
/// \param[in] acn Application class name.
/// \param[in] argc Number of arguments.
/// \param[in] argv Arguments.
PyROOT::RPyROOTApplication::RPyROOTApplication(const char *acn, int *argc, char **argv) : TApplication(acn, argc, argv)
{
   // Save current interpreter context
   gInterpreter->SaveContext();
   gInterpreter->SaveGlobalsContext();

   // Prevent crashes on accessing history
   Gl_histinit((char *)"-");

   // Prevent ROOT from exiting python
   SetReturnFromRun(true);
}

namespace {
static int (*sOldInputHook)() = nullptr;
static PyThreadState *sInputHookEventThreadState = nullptr;

static int EventInputHook()
{
   // This method is supposed to be called from CPython's command line and
   // drives the GUI
   PyEval_RestoreThread(sInputHookEventThreadState);
   gSystem->ProcessEvents();
   PyEval_SaveThread();

   if (sOldInputHook)
      return sOldInputHook();

   return 0;
}

} // unnamed namespace

////////////////////////////////////////////////////////////////////////////
/// \brief Install a method hook for sending events to the GUI.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to an empty Python tuple.
PyObject *PyROOT::RPyROOTApplication::InstallGUIEventInputHook(PyObject * /* self */, PyObject * /* args */)
{
   if (PyOS_InputHook && PyOS_InputHook != &EventInputHook)
      sOldInputHook = PyOS_InputHook;

   sInputHookEventThreadState = PyThreadState_Get();

   PyOS_InputHook = (int (*)()) & EventInputHook;

   Py_RETURN_NONE;
}
<commit_msg>clarify CLI args<commit_after>// Author: Enric Tejedor CERN  04/2019
// Original PyROOT code by Wim Lavrijsen, LBL

/*************************************************************************
 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

// Bindings
#include "Python.h"
#include "CPyCppyy.h"
#include "RPyROOTApplication.h"

// ROOT
#include "TInterpreter.h"
#include "TSystem.h"
#include "TBenchmark.h"
#include "TStyle.h"
#include "TError.h"
#include "Getline.h"
#include "TVirtualMutex.h"

////////////////////////////////////////////////////////////////////////////
/// \brief Create an RPyROOTApplication.
/// \param[in] ignoreCmdLineOpts True if Python command line options should
///            be ignored.
/// \return false if gApplication is not null, true otherwise.
///
/// If ignoreCmdLineOpts is false, this method processes the command line
/// arguments from sys.argv. A distinction between arguments for
/// TApplication and user arguments can be made by using "-" or "--" as a
/// separator on the command line.
///
/// For example, to enable batch mode from the command line:
/// > python script_name.py -b -- user_arg1 ... user_argn
/// or, if the user script receives no arguments:
/// > python script_name.py -b
bool PyROOT::RPyROOTApplication::CreateApplication(int ignoreCmdLineOpts)
{
   if (!gApplication) {
      int argc = 1;
      char **argv = nullptr;

      if (ignoreCmdLineOpts) {
         argv = new char *[argc];
      } else {
         // Retrieve sys.argv list from Python
         PyObject *argl = PySys_GetObject(const_cast<char *>("argv"));

         if (argl && 0 < PyList_Size(argl))
            argc = (int)PyList_GET_SIZE(argl);

         argv = new char *[argc];
         for (int i = 1; i < argc; ++i) {
            char *argi = const_cast<char *>(CPyCppyy_PyText_AsString(PyList_GET_ITEM(argl, i)));
            if (strcmp(argi, "-") == 0 || strcmp(argi, "--") == 0) {
               // Stop collecting options, the remaining are for the Python script
               argc = i; // includes program name
               break;
            }
            argv[i] = argi;
         }
      }

#if PY_VERSION_HEX < 0x03000000
      if (Py_GetProgramName() && strlen(Py_GetProgramName()) != 0)
         argv[0] = Py_GetProgramName();
      else
         argv[0] = (char *)"python";
#else
      argv[0] = (char *)"python";
#endif

      gApplication = new RPyROOTApplication("PyROOT", &argc, argv);
      delete[] argv; // TApplication ctor has copied argv, so done with it

      return true;
   }

   return false;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Setup the basic ROOT globals gBenchmark, gStyle and gProgname,
/// if not already set.
void PyROOT::RPyROOTApplication::InitROOTGlobals()
{
   if (!gBenchmark)
      gBenchmark = new TBenchmark();
   if (!gStyle)
      gStyle = new TStyle();

   if (!gProgName) // should have been set by TApplication
#if PY_VERSION_HEX < 0x03000000
      gSystem->SetProgname(Py_GetProgramName());
#else
      gSystem->SetProgname("python");
#endif
}

////////////////////////////////////////////////////////////////////////////
/// \brief Translate ROOT error/warning to Python.
static void ErrMsgHandler(int level, Bool_t abort, const char *location, const char *msg)
{
   // Initialization from gEnv (the default handler will return w/o msg b/c level too low)
   if (gErrorIgnoreLevel == kUnset)
      ::DefaultErrorHandler(kUnset - 1, kFALSE, "", "");

   if (level < gErrorIgnoreLevel)
      return;

   // Turn warnings into Python warnings
   if (level >= kError) {
      ::DefaultErrorHandler(level, abort, location, msg);
   } else if (level >= kWarning) {
      static const char *emptyString = "";
      if (!location)
         location = emptyString;
      // This warning might be triggered while holding the ROOT lock, while
      // some other thread is holding the GIL and waiting for the ROOT lock.
      // That will trigger a deadlock.
      // So if ROOT is in MT mode, use ROOT's error handler that doesn't take
      // the GIL.
      if (!gGlobalMutex) {
         // Either printout or raise exception, depending on user settings
         PyErr_WarnExplicit(NULL, (char *)msg, (char *)location, 0, (char *)"ROOT", NULL);
      } else {
         ::DefaultErrorHandler(level, abort, location, msg);
      }
   } else {
      ::DefaultErrorHandler(level, abort, location, msg);
   }
}

////////////////////////////////////////////////////////////////////////////
/// \brief Install the ROOT message handler which will turn ROOT error
/// messages into Python exceptions.
void PyROOT::RPyROOTApplication::InitROOTMessageCallback()
{
   SetErrorHandler((ErrorHandlerFunc_t)&ErrMsgHandler);
}

////////////////////////////////////////////////////////////////////////////
/// \brief Initialize an RPyROOTApplication.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args [0] Boolean that tells whether to ignore the command line options.
PyObject *PyROOT::RPyROOTApplication::InitApplication(PyObject * /*self*/, PyObject *args)
{
   int argc = PyTuple_GET_SIZE(args);
   if (argc == 1) {
      PyObject *ignoreCmdLineOpts = PyTuple_GetItem(args, 0);

      if (!PyBool_Check(ignoreCmdLineOpts)) {
         PyErr_SetString(PyExc_TypeError, "Expected boolean type as argument.");
         return nullptr;
      }

      if (CreateApplication(PyObject_IsTrue(ignoreCmdLineOpts))) {
         InitROOTGlobals();
         InitROOTMessageCallback();
      }
   } else {
      PyErr_Format(PyExc_TypeError, "Expected 1 argument, %d passed.", argc);
      return nullptr;
   }

   Py_RETURN_NONE;
}

////////////////////////////////////////////////////////////////////////////
/// \brief Construct a TApplication for PyROOT.
/// \param[in] acn Application class name.
/// \param[in] argc Number of arguments.
/// \param[in] argv Arguments.
PyROOT::RPyROOTApplication::RPyROOTApplication(const char *acn, int *argc, char **argv) : TApplication(acn, argc, argv)
{
   // Save current interpreter context
   gInterpreter->SaveContext();
   gInterpreter->SaveGlobalsContext();

   // Prevent crashes on accessing history
   Gl_histinit((char *)"-");

   // Prevent ROOT from exiting python
   SetReturnFromRun(true);
}

namespace {
static int (*sOldInputHook)() = nullptr;
static PyThreadState *sInputHookEventThreadState = nullptr;

static int EventInputHook()
{
   // This method is supposed to be called from CPython's command line and
   // drives the GUI
   PyEval_RestoreThread(sInputHookEventThreadState);
   gSystem->ProcessEvents();
   PyEval_SaveThread();

   if (sOldInputHook)
      return sOldInputHook();

   return 0;
}

} // unnamed namespace

////////////////////////////////////////////////////////////////////////////
/// \brief Install a method hook for sending events to the GUI.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to an empty Python tuple.
PyObject *PyROOT::RPyROOTApplication::InstallGUIEventInputHook(PyObject * /* self */, PyObject * /* args */)
{
   if (PyOS_InputHook && PyOS_InputHook != &EventInputHook)
      sOldInputHook = PyOS_InputHook;

   sInputHookEventThreadState = PyThreadState_Get();

   PyOS_InputHook = (int (*)()) & EventInputHook;

   Py_RETURN_NONE;
}
<|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (c) 2012-2019 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#include <DTK_DetailsTreeVisualization.hpp>
#include <DTK_LinearBVH.hpp>

#include <Kokkos_Core.hpp>
#include <Kokkos_DefaultNode.hpp>

#include <algorithm>
#include <fstream>
#include <random>

#include <point_clouds.hpp>

template <typename TreeType>
void viz()
{
    using DeviceType = typename TreeType::device_type;
    using ExecutionSpace = typename DeviceType::execution_space;
    Kokkos::View<DataTransferKit::Point *, DeviceType> points( "points" );
    loadPointCloud( "/scratch/source/trilinos/release/DataTransferKit/packages/"
                    "Search/examples/point_clouds/leaf_cloud.txt",
                    points );

    TreeType bvh( points );

    std::fstream fout;

    // Print the entire tree
    std::string const prefix = "trash_";
    fout.open( prefix + "tree_all_nodes_and_edges.dot.m4", std::fstream::out );
    using TreeVisualization =
        typename DataTransferKit::Details::TreeVisualization<DeviceType>;
    using GraphvizVisitor = typename TreeVisualization::GraphvizVisitor;
    TreeVisualization::visitAllIterative( bvh, GraphvizVisitor{fout} );
    fout.close();

    int const n_neighbors = 10;
    int const n_queries = bvh.size();
    Kokkos::View<DataTransferKit::Nearest<DataTransferKit::Point> *, DeviceType>
        queries( "queries", n_queries );
    Kokkos::parallel_for( Kokkos::RangePolicy<ExecutionSpace>( 0, n_queries ),
                          KOKKOS_LAMBDA( int i ) {
                              queries( i ) = DataTransferKit::nearest(
                                  points( i ), n_neighbors );
                          } );
    Kokkos::fence();

    for ( int i = 0; i < n_queries; ++i )
    {
        fout.open( prefix + "untouched_" + std::to_string( i ) +
                       "_nearest_traversal.dot.m4",
                   std::fstream::out );
        TreeVisualization::visit( bvh, queries( i ), GraphvizVisitor{fout} );
        fout.close();
    }

    // Shuffle the queries
    std::random_device rd;
    std::mt19937 g( rd() );
    std::shuffle( queries.data(), queries.data() + queries.size(), g );
    for ( int i = 0; i < n_queries; ++i )
    {
        fout.open( prefix + "shuffled_" + std::to_string( i ) +
                       "_nearest_traversal.dot.m4",
                   std::fstream::out );
        TreeVisualization::visit( bvh, queries( i ), GraphvizVisitor{fout} );
        fout.close();
    }

    // Sort them
    auto permute = DataTransferKit::Details::BatchedQueries<
        DeviceType>::sortQueriesAlongZOrderCurve( bvh.bounds(), queries );
    queries =
        DataTransferKit::Details::BatchedQueries<DeviceType>::applyPermutation(
            permute, queries );
    for ( int i = 0; i < n_queries; ++i )
    {
        fout.open( prefix + "sorted_" + std::to_string( i ) +
                       "_nearest_traversal.dot.m4",
                   std::fstream::out );
        TreeVisualization::visit( bvh, queries( i ), GraphvizVisitor{fout} );
        fout.close();
    }
}

int main( int argc, char *argv[] )
{
    Kokkos::initialize( argc, argv );

    using Serial = Kokkos::Compat::KokkosSerialWrapperNode::device_type;
    using Tree = DataTransferKit::BVH<Serial>;
    viz<Tree>();

    Kokkos::finalize();

    return 0;
}
<commit_msg>Print the point cloud in TikZ format<commit_after>/****************************************************************************
 * Copyright (c) 2012-2019 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#include <DTK_DetailsTreeVisualization.hpp>
#include <DTK_LinearBVH.hpp>

#include <Kokkos_Core.hpp>
#include <Kokkos_DefaultNode.hpp>

#include <algorithm>
#include <fstream>
#include <random>

#include <point_clouds.hpp>

template <typename View>
void printPointCloud( View points, std::ostream &os )
{
    auto const n = points.extent_int( 0 );
    for ( int i = 0; i < n; ++i )
        os << "\\node[leaf] at (" << points( i )[0] << "," << points( i )[1]
           << ") {\\textbullet};\n";
}

template <typename TreeType>
void viz()
{
    using DeviceType = typename TreeType::device_type;
    using ExecutionSpace = typename DeviceType::execution_space;
    Kokkos::View<DataTransferKit::Point *, DeviceType> points( "points" );
    loadPointCloud( "/scratch/source/trilinos/release/DataTransferKit/packages/"
                    "Search/examples/point_clouds/leaf_cloud.txt",
                    points );

    TreeType bvh( points );

    std::fstream fout;
    std::string const prefix = "trash_";

    // Print the point cloud
    fout.open( prefix + "points.tex", std::fstream::out );
    printPointCloud( points, fout );
    fout.close();

    // Print the entire tree
    fout.open( prefix + "tree_all_nodes_and_edges.dot.m4", std::fstream::out );
    using TreeVisualization =
        typename DataTransferKit::Details::TreeVisualization<DeviceType>;
    using GraphvizVisitor = typename TreeVisualization::GraphvizVisitor;
    TreeVisualization::visitAllIterative( bvh, GraphvizVisitor{fout} );
    fout.close();

    int const n_neighbors = 10;
    int const n_queries = bvh.size();
    Kokkos::View<DataTransferKit::Nearest<DataTransferKit::Point> *, DeviceType>
        queries( "queries", n_queries );
    Kokkos::parallel_for( Kokkos::RangePolicy<ExecutionSpace>( 0, n_queries ),
                          KOKKOS_LAMBDA( int i ) {
                              queries( i ) = DataTransferKit::nearest(
                                  points( i ), n_neighbors );
                          } );
    Kokkos::fence();

    for ( int i = 0; i < n_queries; ++i )
    {
        fout.open( prefix + "untouched_" + std::to_string( i ) +
                       "_nearest_traversal.dot.m4",
                   std::fstream::out );
        TreeVisualization::visit( bvh, queries( i ), GraphvizVisitor{fout} );
        fout.close();
    }

    // Shuffle the queries
    std::random_device rd;
    std::mt19937 g( rd() );
    std::shuffle( queries.data(), queries.data() + queries.size(), g );
    for ( int i = 0; i < n_queries; ++i )
    {
        fout.open( prefix + "shuffled_" + std::to_string( i ) +
                       "_nearest_traversal.dot.m4",
                   std::fstream::out );
        TreeVisualization::visit( bvh, queries( i ), GraphvizVisitor{fout} );
        fout.close();
    }

    // Sort them
    auto permute = DataTransferKit::Details::BatchedQueries<
        DeviceType>::sortQueriesAlongZOrderCurve( bvh.bounds(), queries );
    queries =
        DataTransferKit::Details::BatchedQueries<DeviceType>::applyPermutation(
            permute, queries );
    for ( int i = 0; i < n_queries; ++i )
    {
        fout.open( prefix + "sorted_" + std::to_string( i ) +
                       "_nearest_traversal.dot.m4",
                   std::fstream::out );
        TreeVisualization::visit( bvh, queries( i ), GraphvizVisitor{fout} );
        fout.close();
    }
}

int main( int argc, char *argv[] )
{
    Kokkos::initialize( argc, argv );

    using Serial = Kokkos::Compat::KokkosSerialWrapperNode::device_type;
    using Tree = DataTransferKit::BVH<Serial>;
    viz<Tree>();

    Kokkos::finalize();

    return 0;
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2014 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "expression_editor/ExpressionTreeUtils.h"

#include "expression_editor/Value.h"
#include "expression_editor/Empty.h"
#include "expression_editor/Operator.h"
#include "expression_editor/UnfinishedOperator.h"
#include "expression_editor/OperatorDescriptor.h"

namespace Interaction {

void ExpressionTreeUtils::fixTop(Expression*& top)
{
	fixPrecedence(top);
	fixWrongIds(top);
}

Expression* ExpressionTreeUtils::replace(Expression*& top, Expression* oldExpr, Expression* newExpr)
{
	if (oldExpr == top)
	{
		top = newExpr;
		newExpr->setParent(nullptr);
		return oldExpr;
	}
	else
		return oldExpr->parent()->replaceOperand(oldExpr, newExpr);
}

void ExpressionTreeUtils::rotateRight(Expression*& top, Operator* child, Operator* parent)
{
	parent->first(true);
	replace(top, parent, child);
	Expression* branch = child->last(true);
	child->append(parent);
	parent->prepend(branch);

}

void ExpressionTreeUtils::rotateLeft(Expression*& top, Operator* child, Operator* parent)
{
	parent->last(true);
	replace(top, parent, child);
	Expression* branch = child->first(true);
	child->prepend(parent);
	parent->append(branch);
}

void ExpressionTreeUtils::fixPrecedence(Expression*& top)
{
	bool more_iterations_needed = true;
	while (more_iterations_needed ) more_iterations_needed = fixExprPrecedence(top, top);
}

bool ExpressionTreeUtils::fixExprPrecedence(Expression*& top, Expression* e)
{
	if ( dynamic_cast<Value*> (e)) return false;
	if ( dynamic_cast<Empty*> (e)) return false;

	Operator* op = dynamic_cast<Operator*> (e);

	bool more_iterations_needed = true;
	while (more_iterations_needed)
	{
		more_iterations_needed = false;

		// Fix all children
		for (int operand = 0; operand < op->size(); ++operand)
			more_iterations_needed = fixExprPrecedence(top, op->at(operand)) || more_iterations_needed;
	}

	//Look left
	if (op->descriptor()->prefix().isEmpty())
	{
		Operator* left = dynamic_cast<Operator*> (op->first());
		if (left && left->descriptor()->postfix().isEmpty())
		{
			if (op->descriptor()->precedence() < left->descriptor()->precedence() // Must rotate because of precedence

				 // Must rotate because of associativity. This assumes that the associativity of different operators at
				 // the same precedence level is the same.
				 || ( (op->descriptor()->precedence() == left->descriptor()->precedence())
						&& op->descriptor()->associativity() == OperatorDescriptor::RightAssociative)
				 )
			{
				rotateRight(top, left, op);
				return true;
			}
		}
	}

	//Look right
	if (op->descriptor()->postfix().isEmpty())
	{
		Operator* right = dynamic_cast<Operator*> (op->last());
		if (right && right->descriptor()->prefix().isEmpty())
		{
			if (op->descriptor()->precedence() < right->descriptor()->precedence() // Must rotate because of precedence

				 // Must rotate because of associativity. This assumes that the associativity of different operators at
				 // the same precedence level is the same.
				 || ( (op->descriptor()->precedence() == right->descriptor()->precedence())
						&& op->descriptor()->associativity() == OperatorDescriptor::LeftAssociative)
				 )
			{
				rotateLeft(top, right, op);
				return true;
			}
		}
	}

	return false;
}

void ExpressionTreeUtils::grow(Expression*& top, Operator* op, bool leftside)
{
	bool rightside = !leftside;

	// Can't grow if there is no parent
	if ( !op->parent() )
		return;

	// Can't grow from a side where there is no delimiter
	if ( (leftside && op->descriptor()->prefix().isEmpty() ) || (rightside && op->descriptor()->postfix().isEmpty()) )
		return;

	Operator* parent = op->parent();

	// Get context
	int delim_begin;
	int delim_end;
	op->globalDelimiterBoundaries(leftside ? 0 : op->descriptor()->numOperands(), delim_begin, delim_end);
	ExpressionContext c = top->findContext(leftside ? delim_begin: delim_end);

	// If this is an expression in the middle of two delimiters that belong to the same operator
	// this typically means that it can not be grown any more from only a single side...
	bool wrap_parent = false;
	if (   ( leftside && (c.leftType() == ExpressionContext::None || c.leftType() == ExpressionContext::OpBoundary) )
		 || ( rightside && (c.rightType() == ExpressionContext::None || c.rightType() == ExpressionContext::OpBoundary) )
			 )
	{
		// .. EXCEPT: when both delimiters are the same as the delimiter we're trying to grow and the
		// direction opposite of the growth direction is an end delimiter. In that case we simply
		// engulf the entire parent.
		op->globalDelimiterBoundaries(leftside ? op->descriptor()->numOperands() : 0, delim_begin, delim_end);
		ExpressionContext c_other = top->findContext(leftside ? delim_end : delim_begin );
		if (   ( leftside && c_other.rightType() == ExpressionContext::OpBoundary
					&& c_other.rightText() == op->descriptor()->postfix()
					&& c_other.rightDelim() == c_other.rightOp()->size())
			 || ( rightside && c_other.leftType() == ExpressionContext::OpBoundary
					&& c_other.leftText() == op->descriptor()->prefix() && c_other.leftDelim() == 0) )
			wrap_parent = true;
		else
		return;
	}

	// Special case when the parent ends with a pre/postfix in the direction we're growing.
	// In that case we must wrap the whole operator as we can not break the delimiters.
	wrap_parent = wrap_parent || ( !(leftside && parent->descriptor()->prefix().isEmpty())
											 && !(rightside && parent->descriptor()->postfix().isEmpty()));
	if (wrap_parent)
	{
		Expression* placeholder = new Empty();
		replace(top, parent, placeholder);
		replace(top, op, leftside ? op->first(true) : op->last(true));
		if (leftside) op->prepend(parent);
		else op->append(parent);
		delete replace(top, placeholder, op);

		return;
	}

	// Find the expression that must be wrapped
	Operator* top_op = parent;
	Operator* child = op;
	while ( (leftside ? top_op->last() : top_op->first()) != child)
	{
		child = top_op;
		top_op = top_op->parent();
		if (!top_op) return;
	}
	Expression* to_wrap = leftside ? top_op->first()->smallestRightmostSubExpr()
											 : top_op->last()->smallestLeftmostSubExpr();

	// Do the exchange --------------------------------------

	// Disconnect top_op from the the entire tree and from it's first and last
	// Note that if we've reached this point then first and last must be two different nodes
	Expression* top_op_placeholder = new Empty();
	replace(top, top_op, top_op_placeholder);
	Expression* top_op_last = top_op->last(true);   // Special case when rightside: top_op_last == to_wrap
	Expression* top_op_first = top_op->first(true); // Special case when leftside: top_op_first == to_wrap

	// Disconnect the to_wrap expression if not yet disconnected
	Expression* to_wrap_placeholder = nullptr;
	if ( (leftside && to_wrap != top_op_first) || (rightside && to_wrap != top_op_last) )
	{
		to_wrap_placeholder = new Empty();
		replace(top, to_wrap, to_wrap_placeholder);
	}

	// Disconnect the old_wrapped expression
	Expression* old_wrap = leftside ? op->first(true) : op->last(true); // This is the content that was previously wrapped
	// Disconnect the left and right children of top_op.

	// Make the necessary connections
	if (leftside)
	{
		op->prepend(top_op);
		top_op->prepend(to_wrap);
		top_op->append(old_wrap);
		//Consider the special case
		if (top_op_first == to_wrap)
		{
			delete replace(top, top_op_placeholder, top_op_last );
		}
		else
		{
			delete replace(top, top_op_placeholder, top_op_first );
			delete replace(top, to_wrap_placeholder, top_op_last);
		}
	}
	else
	{
		op->append(top_op);
		top_op->prepend(old_wrap);
		top_op->append(to_wrap);
		//Consider the special case
		if (top_op_last == to_wrap)
		{
			delete replace(top, top_op_placeholder, top_op_first );
		}
		else
		{
			delete replace(top, top_op_placeholder, top_op_last );
			delete replace(top, to_wrap_placeholder, top_op_first);
		}
	}

	fixTop(top);
}

void ExpressionTreeUtils::shrink(Expression*& top, Operator* op, bool leftside)
{
	// Can't shrink if only an atomic value left
	if ( ( leftside ? op->first()->type() : op->last()->type() ) != Operator::type() )
		return;

	// Can't shrink from a side where there is no delimiter
	if ( (leftside && op->descriptor()->prefix().isEmpty() ) || (!leftside && op->descriptor()->postfix().isEmpty()))
		return;

	Expression* new_border_expr = (leftside ? op->first() : op->last())
			->findCutExpression(leftside, leftside ? op->descriptor()->postfix() : op->descriptor()->prefix());
	if (new_border_expr == nullptr) return;

	Operator* cut_op = new_border_expr->parent();
	Operator* cut_op_parent = cut_op->parent();

	// Rewire the tree
	Expression* op_placeholder = new Empty;
	replace(top, op, op_placeholder);

	if (leftside)
	{
		cut_op->last(true);
		cut_op_parent->first(true);
		cut_op_parent->prepend(new_border_expr);
		cut_op->append(op);
	}
	else
	{
		cut_op->first(true);
		cut_op_parent->last(true);
		cut_op_parent->append(new_border_expr);
		cut_op->prepend(op);
	}

	delete replace(top, op_placeholder, cut_op);

	fixTop(top);
}

void ExpressionTreeUtils::fixWrongIds(Expression*& top)
{
	QList<Expression*> toFix;
	toFix << top;

	while (!toFix.isEmpty())
	{
		auto e = toFix.first();
		toFix.removeFirst();

		if (auto op = dynamic_cast<Operator*>(e))
		{
			bool unfinished = dynamic_cast<UnfinishedOperator*>(op);
			if (!unfinished)
			{
				bool badId = false;
				int operandIndex = 0;
				for (auto s : op->descriptor()->signature())
				{
					if (s == "id")
					{
						auto v = dynamic_cast<Value*> (op->operands().at(operandIndex));
						badId = badId || !v || v->text().isEmpty() || !(v->text()[0].isLetter() || v->text()[0] == '_');
						if (badId) break;
					}

					if (!OperatorDescriptor::isDelimiter(s)) ++operandIndex;
				}

				if (badId) op = UnfinishedOperator::replaceFinishedWithUnfinished(top, op);
			}

			for (auto operand : op->operands())
				toFix.append(operand);
		}
	}
}

} /* namespace InteractionBase */
<commit_msg>Fix a crash when an error expression contained the string "id"<commit_after>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2014 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "expression_editor/ExpressionTreeUtils.h"

#include "expression_editor/Value.h"
#include "expression_editor/Empty.h"
#include "expression_editor/Operator.h"
#include "expression_editor/UnfinishedOperator.h"
#include "expression_editor/ErrorDescriptor.h"
#include "expression_editor/OperatorDescriptor.h"

namespace Interaction {

void ExpressionTreeUtils::fixTop(Expression*& top)
{
	fixPrecedence(top);
	fixWrongIds(top);
}

Expression* ExpressionTreeUtils::replace(Expression*& top, Expression* oldExpr, Expression* newExpr)
{
	if (oldExpr == top)
	{
		top = newExpr;
		newExpr->setParent(nullptr);
		return oldExpr;
	}
	else
		return oldExpr->parent()->replaceOperand(oldExpr, newExpr);
}

void ExpressionTreeUtils::rotateRight(Expression*& top, Operator* child, Operator* parent)
{
	parent->first(true);
	replace(top, parent, child);
	Expression* branch = child->last(true);
	child->append(parent);
	parent->prepend(branch);

}

void ExpressionTreeUtils::rotateLeft(Expression*& top, Operator* child, Operator* parent)
{
	parent->last(true);
	replace(top, parent, child);
	Expression* branch = child->first(true);
	child->prepend(parent);
	parent->append(branch);
}

void ExpressionTreeUtils::fixPrecedence(Expression*& top)
{
	bool more_iterations_needed = true;
	while (more_iterations_needed ) more_iterations_needed = fixExprPrecedence(top, top);
}

bool ExpressionTreeUtils::fixExprPrecedence(Expression*& top, Expression* e)
{
	if ( dynamic_cast<Value*> (e)) return false;
	if ( dynamic_cast<Empty*> (e)) return false;

	Operator* op = dynamic_cast<Operator*> (e);

	bool more_iterations_needed = true;
	while (more_iterations_needed)
	{
		more_iterations_needed = false;

		// Fix all children
		for (int operand = 0; operand < op->size(); ++operand)
			more_iterations_needed = fixExprPrecedence(top, op->at(operand)) || more_iterations_needed;
	}

	//Look left
	if (op->descriptor()->prefix().isEmpty())
	{
		Operator* left = dynamic_cast<Operator*> (op->first());
		if (left && left->descriptor()->postfix().isEmpty())
		{
			if (op->descriptor()->precedence() < left->descriptor()->precedence() // Must rotate because of precedence

				 // Must rotate because of associativity. This assumes that the associativity of different operators at
				 // the same precedence level is the same.
				 || ( (op->descriptor()->precedence() == left->descriptor()->precedence())
						&& op->descriptor()->associativity() == OperatorDescriptor::RightAssociative)
				 )
			{
				rotateRight(top, left, op);
				return true;
			}
		}
	}

	//Look right
	if (op->descriptor()->postfix().isEmpty())
	{
		Operator* right = dynamic_cast<Operator*> (op->last());
		if (right && right->descriptor()->prefix().isEmpty())
		{
			if (op->descriptor()->precedence() < right->descriptor()->precedence() // Must rotate because of precedence

				 // Must rotate because of associativity. This assumes that the associativity of different operators at
				 // the same precedence level is the same.
				 || ( (op->descriptor()->precedence() == right->descriptor()->precedence())
						&& op->descriptor()->associativity() == OperatorDescriptor::LeftAssociative)
				 )
			{
				rotateLeft(top, right, op);
				return true;
			}
		}
	}

	return false;
}

void ExpressionTreeUtils::grow(Expression*& top, Operator* op, bool leftside)
{
	bool rightside = !leftside;

	// Can't grow if there is no parent
	if ( !op->parent() )
		return;

	// Can't grow from a side where there is no delimiter
	if ( (leftside && op->descriptor()->prefix().isEmpty() ) || (rightside && op->descriptor()->postfix().isEmpty()) )
		return;

	Operator* parent = op->parent();

	// Get context
	int delim_begin;
	int delim_end;
	op->globalDelimiterBoundaries(leftside ? 0 : op->descriptor()->numOperands(), delim_begin, delim_end);
	ExpressionContext c = top->findContext(leftside ? delim_begin: delim_end);

	// If this is an expression in the middle of two delimiters that belong to the same operator
	// this typically means that it can not be grown any more from only a single side...
	bool wrap_parent = false;
	if (   ( leftside && (c.leftType() == ExpressionContext::None || c.leftType() == ExpressionContext::OpBoundary) )
		 || ( rightside && (c.rightType() == ExpressionContext::None || c.rightType() == ExpressionContext::OpBoundary) )
			 )
	{
		// .. EXCEPT: when both delimiters are the same as the delimiter we're trying to grow and the
		// direction opposite of the growth direction is an end delimiter. In that case we simply
		// engulf the entire parent.
		op->globalDelimiterBoundaries(leftside ? op->descriptor()->numOperands() : 0, delim_begin, delim_end);
		ExpressionContext c_other = top->findContext(leftside ? delim_end : delim_begin );
		if (   ( leftside && c_other.rightType() == ExpressionContext::OpBoundary
					&& c_other.rightText() == op->descriptor()->postfix()
					&& c_other.rightDelim() == c_other.rightOp()->size())
			 || ( rightside && c_other.leftType() == ExpressionContext::OpBoundary
					&& c_other.leftText() == op->descriptor()->prefix() && c_other.leftDelim() == 0) )
			wrap_parent = true;
		else
		return;
	}

	// Special case when the parent ends with a pre/postfix in the direction we're growing.
	// In that case we must wrap the whole operator as we can not break the delimiters.
	wrap_parent = wrap_parent || ( !(leftside && parent->descriptor()->prefix().isEmpty())
											 && !(rightside && parent->descriptor()->postfix().isEmpty()));
	if (wrap_parent)
	{
		Expression* placeholder = new Empty();
		replace(top, parent, placeholder);
		replace(top, op, leftside ? op->first(true) : op->last(true));
		if (leftside) op->prepend(parent);
		else op->append(parent);
		delete replace(top, placeholder, op);

		return;
	}

	// Find the expression that must be wrapped
	Operator* top_op = parent;
	Operator* child = op;
	while ( (leftside ? top_op->last() : top_op->first()) != child)
	{
		child = top_op;
		top_op = top_op->parent();
		if (!top_op) return;
	}
	Expression* to_wrap = leftside ? top_op->first()->smallestRightmostSubExpr()
											 : top_op->last()->smallestLeftmostSubExpr();

	// Do the exchange --------------------------------------

	// Disconnect top_op from the the entire tree and from it's first and last
	// Note that if we've reached this point then first and last must be two different nodes
	Expression* top_op_placeholder = new Empty();
	replace(top, top_op, top_op_placeholder);
	Expression* top_op_last = top_op->last(true);   // Special case when rightside: top_op_last == to_wrap
	Expression* top_op_first = top_op->first(true); // Special case when leftside: top_op_first == to_wrap

	// Disconnect the to_wrap expression if not yet disconnected
	Expression* to_wrap_placeholder = nullptr;
	if ( (leftside && to_wrap != top_op_first) || (rightside && to_wrap != top_op_last) )
	{
		to_wrap_placeholder = new Empty();
		replace(top, to_wrap, to_wrap_placeholder);
	}

	// Disconnect the old_wrapped expression
	Expression* old_wrap = leftside ? op->first(true) : op->last(true); // This is the content that was previously wrapped
	// Disconnect the left and right children of top_op.

	// Make the necessary connections
	if (leftside)
	{
		op->prepend(top_op);
		top_op->prepend(to_wrap);
		top_op->append(old_wrap);
		//Consider the special case
		if (top_op_first == to_wrap)
		{
			delete replace(top, top_op_placeholder, top_op_last );
		}
		else
		{
			delete replace(top, top_op_placeholder, top_op_first );
			delete replace(top, to_wrap_placeholder, top_op_last);
		}
	}
	else
	{
		op->append(top_op);
		top_op->prepend(old_wrap);
		top_op->append(to_wrap);
		//Consider the special case
		if (top_op_last == to_wrap)
		{
			delete replace(top, top_op_placeholder, top_op_first );
		}
		else
		{
			delete replace(top, top_op_placeholder, top_op_last );
			delete replace(top, to_wrap_placeholder, top_op_first);
		}
	}

	fixTop(top);
}

void ExpressionTreeUtils::shrink(Expression*& top, Operator* op, bool leftside)
{
	// Can't shrink if only an atomic value left
	if ( ( leftside ? op->first()->type() : op->last()->type() ) != Operator::type() )
		return;

	// Can't shrink from a side where there is no delimiter
	if ( (leftside && op->descriptor()->prefix().isEmpty() ) || (!leftside && op->descriptor()->postfix().isEmpty()))
		return;

	Expression* new_border_expr = (leftside ? op->first() : op->last())
			->findCutExpression(leftside, leftside ? op->descriptor()->postfix() : op->descriptor()->prefix());
	if (new_border_expr == nullptr) return;

	Operator* cut_op = new_border_expr->parent();
	Operator* cut_op_parent = cut_op->parent();

	// Rewire the tree
	Expression* op_placeholder = new Empty;
	replace(top, op, op_placeholder);

	if (leftside)
	{
		cut_op->last(true);
		cut_op_parent->first(true);
		cut_op_parent->prepend(new_border_expr);
		cut_op->append(op);
	}
	else
	{
		cut_op->first(true);
		cut_op_parent->last(true);
		cut_op_parent->append(new_border_expr);
		cut_op->prepend(op);
	}

	delete replace(top, op_placeholder, cut_op);

	fixTop(top);
}

void ExpressionTreeUtils::fixWrongIds(Expression*& top)
{
	QList<Expression*> toFix;
	toFix << top;

	while (!toFix.isEmpty())
	{
		auto e = toFix.first();
		toFix.removeFirst();

		if (auto op = dynamic_cast<Operator*>(e))
		{
			bool isUnfinished = dynamic_cast<UnfinishedOperator*>(op);
			if (!isUnfinished)
			{
				bool isError = dynamic_cast<ErrorDescriptor*>(op->descriptor());
				if (!isError)
				{
					bool badId = false;
					int operandIndex = 0;
					for (auto s : op->descriptor()->signature())
					{
						if (s == "id")
						{
							auto v = dynamic_cast<Value*> (op->operands().at(operandIndex));
							badId = badId || !v || v->text().isEmpty() || !(v->text()[0].isLetter() || v->text()[0] == '_');
							if (badId) break;
						}

						if (!OperatorDescriptor::isDelimiter(s)) ++operandIndex;
					}

					if (badId) op = UnfinishedOperator::replaceFinishedWithUnfinished(top, op);
				}
			}

			for (auto operand : op->operands())
				toFix.append(operand);
		}
	}
}

} /* namespace InteractionBase */
<|endoftext|>