<commit_before>#ifndef CONFIG_HPP
#define CONFIG_HPP

#include <sys/types.h>
#include <sys/sysctl.h>
#include "bridge.h"
#include "../../bridge/output/include.bridge_essential_configuration_enum.h"

namespace org_pqrs_Karabiner {
class Config final {
public:
  static void sysctl_register(void);
  static void sysctl_unregister(void);

  // ----------------------------------------
  static void set_initialized(bool newvalue);
  static bool get_initialized(void);
  static bool get_debug(void);
  static bool get_debug_devel(void);
  static bool get_debug_pointing(void);

  // ----------------------------------------
  static void set_essential_config(const int32_t* newvalues, size_t num);
  static bool set_essential_config_one(uint32_t index, int32_t value);

  static int get_essential_config(unsigned int index) {
    if (index >= BRIDGE_ESSENTIAL_CONFIG_INDEX__END__) {
      return 0;
    }
    return essential_config_[index];
  }

  static unsigned int get_repeat_initial_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_initial_wait);
    if (get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_general_unlimited_key_repeat_rate)) {
      return getvalue(v, 1);
    } else {
      return getvalue(v, 200);
    }
  }
  static unsigned int get_repeat_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_wait);
    if (get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_general_unlimited_key_repeat_rate)) {
      return getvalue(v, 1);
    } else {
      return getvalue(v, 5);
    }
  }
  static unsigned int get_repeat_consumer_initial_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_consumer_initial_wait);
    return getvalue(v, 10);
  }
  static unsigned int get_repeat_consumer_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_consumer_wait);
    return getvalue(v, 10);
  }
  static unsigned int get_wait_before_and_after_a_modifier_key_event(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_wait_before_and_after_a_modifier_key_event);
    return getvalue(v, 0, 100);
  }
  static unsigned int get_wait_before_and_after_a_click_event(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_wait_before_and_after_a_click_event);
    return getvalue(v, 0, 100);
  }
  static unsigned int get_keyoverlaidmodifier_initial_modifier_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_keyoverlaidmodifier_initial_modifier_wait);
    return getvalue(v, 0);
  }
  static unsigned int get_keyoverlaidmodifier_initial_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_keyoverlaidmodifier_initial_wait);
    return getvalue(v, 200);
  }
  static unsigned int get_keyoverlaidmodifier_timeout(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_keyoverlaidmodifier_timeout);
    return getvalue(v, 0);
  }
  static unsigned int get_ignore_bouncing_threshold_for_keyboard(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_ignore_bouncing_threshold_for_keyboard);
    return getvalue(v, 0, 1000);
  }
  static unsigned int get_ignore_bouncing_threshold_for_mice(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_ignore_bouncing_threshold_for_mice);
    return getvalue(v, 0, 1000);
  }
  static unsigned int get_simultaneouskeypresses_delay(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_simultaneouskeypresses_delay);
    return getvalue(v, 5, 1000);
  }
  static unsigned int get_simultaneouskeypresses_pointingbutton_delay(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_simultaneouskeypresses_pointingbutton_delay);
    return getvalue(v, 5, 1000);
  }
  static unsigned int get_holdingkeytokey_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_holdingkeytokey_wait);
    return getvalue(v, 10);
  }
  static unsigned int get_mousekey_high_speed_of_pointer(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_high_speed_of_pointer);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_initial_wait_of_pointer(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_initial_wait_of_pointer);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_repeat_wait_of_pointer(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_repeat_wait_of_pointer);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_high_speed_of_scroll(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_high_speed_of_scroll);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_initial_wait_of_scroll(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_initial_wait_of_scroll);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_repeat_wait_of_scroll(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_repeat_wait_of_scroll);
    return getvalue(v, 0);
  }
  static unsigned int get_fixed_distance_magnification(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_fixed_distance_magnification);
    return getvalue(v, 0);
  }

private:
  static unsigned int getvalue(int value, int minval) {
    if (value < minval) return minval;
    return value;
  }
  static unsigned int getvalue(int value, int minval, int maxval) {
    if (value < minval) return minval;
    if (value > maxval) return maxval;
    return value;
  }

  static void load_essential_config_default(void);

  static int essential_config_[BRIDGE_ESSENTIAL_CONFIG_INDEX__END__];
  static const int essential_config_default_[BRIDGE_ESSENTIAL_CONFIG_INDEX__END__];
};
}

#endif
<commit_msg>increase min value of Config::get_wait_before_and_after_*<commit_after>#ifndef CONFIG_HPP
#define CONFIG_HPP

#include <sys/types.h>
#include <sys/sysctl.h>
#include "bridge.h"
#include "../../bridge/output/include.bridge_essential_configuration_enum.h"

namespace org_pqrs_Karabiner {
class Config final {
public:
  static void sysctl_register(void);
  static void sysctl_unregister(void);

  // ----------------------------------------
  static void set_initialized(bool newvalue);
  static bool get_initialized(void);
  static bool get_debug(void);
  static bool get_debug_devel(void);
  static bool get_debug_pointing(void);

  // ----------------------------------------
  static void set_essential_config(const int32_t* newvalues, size_t num);
  static bool set_essential_config_one(uint32_t index, int32_t value);

  static int get_essential_config(unsigned int index) {
    if (index >= BRIDGE_ESSENTIAL_CONFIG_INDEX__END__) {
      return 0;
    }
    return essential_config_[index];
  }

  static unsigned int get_repeat_initial_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_initial_wait);
    if (get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_general_unlimited_key_repeat_rate)) {
      return getvalue(v, 1);
    } else {
      return getvalue(v, 200);
    }
  }
  static unsigned int get_repeat_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_wait);
    if (get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_general_unlimited_key_repeat_rate)) {
      return getvalue(v, 1);
    } else {
      return getvalue(v, 5);
    }
  }
  static unsigned int get_repeat_consumer_initial_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_consumer_initial_wait);
    return getvalue(v, 10);
  }
  static unsigned int get_repeat_consumer_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_consumer_wait);
    return getvalue(v, 10);
  }
  static unsigned int get_wait_before_and_after_a_modifier_key_event(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_wait_before_and_after_a_modifier_key_event);
    return getvalue(v, 0, 1000);
  }
  static unsigned int get_wait_before_and_after_a_click_event(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_wait_before_and_after_a_click_event);
    return getvalue(v, 0, 1000);
  }
  static unsigned int get_keyoverlaidmodifier_initial_modifier_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_keyoverlaidmodifier_initial_modifier_wait);
    return getvalue(v, 0);
  }
  static unsigned int get_keyoverlaidmodifier_initial_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_repeat_keyoverlaidmodifier_initial_wait);
    return getvalue(v, 200);
  }
  static unsigned int get_keyoverlaidmodifier_timeout(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_keyoverlaidmodifier_timeout);
    return getvalue(v, 0);
  }
  static unsigned int get_ignore_bouncing_threshold_for_keyboard(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_ignore_bouncing_threshold_for_keyboard);
    return getvalue(v, 0, 1000);
  }
  static unsigned int get_ignore_bouncing_threshold_for_mice(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_ignore_bouncing_threshold_for_mice);
    return getvalue(v, 0, 1000);
  }
  static unsigned int get_simultaneouskeypresses_delay(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_simultaneouskeypresses_delay);
    return getvalue(v, 5, 1000);
  }
  static unsigned int get_simultaneouskeypresses_pointingbutton_delay(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_simultaneouskeypresses_pointingbutton_delay);
    return getvalue(v, 5, 1000);
  }
  static unsigned int get_holdingkeytokey_wait(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_holdingkeytokey_wait);
    return getvalue(v, 10);
  }
  static unsigned int get_mousekey_high_speed_of_pointer(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_high_speed_of_pointer);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_initial_wait_of_pointer(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_initial_wait_of_pointer);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_repeat_wait_of_pointer(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_repeat_wait_of_pointer);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_high_speed_of_scroll(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_high_speed_of_scroll);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_initial_wait_of_scroll(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_initial_wait_of_scroll);
    return getvalue(v, 0);
  }
  static unsigned int get_mousekey_repeat_wait_of_scroll(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_mousekey_repeat_wait_of_scroll);
    return getvalue(v, 0);
  }
  static unsigned int get_fixed_distance_magnification(void) {
    int v = get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_parameter_fixed_distance_magnification);
    return getvalue(v, 0);
  }

private:
  static unsigned int getvalue(int value, int minval) {
    if (value < minval) return minval;
    return value;
  }
  static unsigned int getvalue(int value, int minval, int maxval) {
    if (value < minval) return minval;
    if (value > maxval) return maxval;
    return value;
  }

  static void load_essential_config_default(void);

  static int essential_config_[BRIDGE_ESSENTIAL_CONFIG_INDEX__END__];
  static const int essential_config_default_[BRIDGE_ESSENTIAL_CONFIG_INDEX__END__];
};
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include "poll_manager.h"
#include "de_web_plugin_private.h"

/*! Constructor.
 */
PollManager::PollManager(QObject *parent) :
    QObject(parent)
{
    pollState = StateIdle;
    timer = new QTimer(this);
    timer->setSingleShot(true);
    connect(timer, SIGNAL(timeout()), this, SLOT(pollTimerFired()));
    plugin = qobject_cast<DeRestPluginPrivate*>(parent);
}

/*! Queues polling of the node.
    \param restNode - the node to poll
 */
void PollManager::poll(RestNodeBase *restNode, const QDateTime &tStart)
{
    Resource *r = dynamic_cast<Resource*>(restNode);
    DBG_Assert(r != 0);
    if (!r || !restNode->node())
    {
        return;
    }

    PollItem pitem;

    if (!restNode->node()->nodeDescriptor().receiverOnWhenIdle())
    {
        return;
    }

    LightNode *lightNode = 0;
    Sensor *sensor = 0;

    if (r->prefix() == RLights)
    {
        lightNode = static_cast<LightNode*>(restNode);
        DBG_Assert(lightNode != 0);
        pitem.endpoint = lightNode->haEndpoint().endpoint();
        DBG_Printf(DBG_INFO_L2, ">>>> Poll light node %s\n", qPrintable(lightNode->name()));
    }
    else if (r->prefix() == RSensors)
    {
        sensor = static_cast<Sensor*>(restNode);
        DBG_Assert(sensor != 0);
        pitem.endpoint = sensor->fingerPrint().endpoint;
        DBG_Printf(DBG_INFO_L2, ">>>> Poll %s sensor node %s\n", qPrintable(sensor->type()), qPrintable(sensor->name()));
    }
    else
    {
        return;
    }

    pitem.id = restNode->id();
    pitem.prefix = r->prefix();
    pitem.address = restNode->address();
    pitem.tStart = tStart;

    for (int i = 0; i < r->itemCount(); i++)
    {
        const ResourceItem *item = r->itemForIndex(i);
        const char *suffix = item ? item->descriptor().suffix : 0;

        if (suffix == RStateOn ||
            suffix == RStateBri ||
            suffix == RStateColorMode ||
            (suffix == RStateConsumption && sensor && sensor->type() == QLatin1String("ZHAConsumption")) ||
            (suffix == RStatePower && sensor && sensor->type() == QLatin1String("ZHAPower")) ||
            suffix == RAttrModelId)
        {
            // DBG_Printf(DBG_INFO_L2, "    attribute %s\n", suffix);
            pitem.items.push_back(suffix);
        }
    }

    for (PollItem &i : items)
    {
        if (i.prefix == r->prefix() && i.id == restNode->id())
        {
            i.items = pitem.items; // update
            if (tStart.isValid())
            {
                i.tStart = tStart;
            }
            return;
        }
    }

    items.push_back(pitem);

    if (!timer->isActive())
    {
        timer->start(1);
    }
}

/*! Delays polling for \p ms milliseconds.
 */
void PollManager::delay(int ms)
{
    timer->stop();
    timer->start(ms);
}

/*! Handle APS confirm if related to polling.
 */
void PollManager::apsdeDataConfirm(const deCONZ::ApsDataConfirm &conf)
{
    if (pollState != StateWait)
    {
        return;
    }

    if (apsReqId != conf.id())
    {
        return;
    }

    if (dstAddr.hasExt() && conf.dstAddress().hasExt()
        && dstAddr.ext() != conf.dstAddress().ext())
    {

    }

    else if (dstAddr.hasNwk() && conf.dstAddress().hasNwk()
        && dstAddr.nwk() != conf.dstAddress().nwk())
    {

    }

    DBG_Printf(DBG_INFO_L2, "Poll APS confirm %u status: 0x%02X\n", conf.id(), conf.status());

    pollState = StateIdle;
    timer->stop();
    timer->start(1);
}

/*! Timer callback to proceed polling.
 */
void PollManager::pollTimerFired()
{
    if (pollState == StateWait)
    {
        DBG_Printf(DBG_INFO, "timout on poll APS confirm\n");
        pollState = StateIdle;
    }

    DBG_Assert(pollState == StateIdle);

    if (items.empty())
    {
        plugin->pollNextLight();
        return;
    }

    QDateTime now = QDateTime::currentDateTime();
    PollItem &pitem = items.front();
    Resource *r = plugin->getResource(pitem.prefix, pitem.id);
    ResourceItem *item = 0;
    RestNodeBase *restNode = 0;
    const LightNode *lightNode = 0;
    if (r && r->prefix() == RLights)
    {
        restNode = plugin->getLightNodeForId(pitem.id);
        lightNode = static_cast<LightNode*>(restNode);
        item = r->item(RStateReachable);
    }
    else if (r && r->prefix() == RSensors)
    {
        restNode = plugin->getSensorNodeForId(pitem.id);
        item = r->item(RConfigReachable);
    }

    if (pitem.tStart.isValid() && pitem.tStart > now)
    {
        if (items.size() > 1)
        {
            PollItem tmp = pitem;
            items.front() = items.back();
            items.back() = tmp;
        }
        timer->start(1);
        return;
    }

    if (!r || pitem.items.empty() ||
        !restNode ||
        //!restNode->lastRx().isValid() ||
        !item || !item->toBool()) // not reachable
    {
        items.front() = items.back();
        items.pop_back();
        timer->start(1);
        return;
    }

    quint16 clusterId = 0;
    std::vector<quint16> attributes;

    item = r->item(RStateOn);
    bool isOn = item ? item->toBool() : false;
    const char *&suffix = pitem.items[0];

    for (size_t i = 0; pitem.items[0] == 0 && i < pitem.items.size(); i++)
    {
        if (pitem.items[i] != 0)
        {
            pitem.items[0] = pitem.items[i]; // move to front
            pitem.items[i] = 0; // clear
            break;
        }
    }

    if (!suffix)
    {
        pitem.items.clear(); // all done
    }

    if (suffix == RStateOn)
    {
        clusterId = ONOFF_CLUSTER_ID;
        attributes.push_back(0x0000); // onOff
    }
    else if (suffix == RStateBri && isOn)
    {
        NodeValue &val = restNode->getZclValue(LEVEL_CLUSTER_ID, 0x0000);

        if (isOn || !val.timestamp.isValid())
        {
            clusterId = LEVEL_CLUSTER_ID;
            attributes.push_back(0x0000); // current level
        }
    }
    else if (suffix == RStateColorMode && lightNode)
    {
        clusterId = COLOR_CLUSTER_ID;
        item = r->item(RConfigColorCapabilities);

        if (!item)
        {
            attributes.push_back(0x0008); // color mode
            attributes.push_back(0x4001); // enhanced color mode
            attributes.push_back(0x400a); // color capabilities
            attributes.push_back(0x400b); // color temperature min
            attributes.push_back(0x400c); // color temperature max
        }
        else
        {
            quint16 cap = item->toNumber();
            std::vector<quint16> toCheck;
            if (cap & 0x0002) // enhanced hue supported
            {
                toCheck.push_back(0x4001); // enhanced color mode
                toCheck.push_back(0x4000); // enhanced hue
                toCheck.push_back(0x0001); // saturation
            }
            else if (cap & 0x0001)
            {
                toCheck.push_back(0x0000); // hue
                toCheck.push_back(0x0001); // saturation
                toCheck.push_back(0x0008); // color mode
            }
            else
            {
                toCheck.push_back(0x0008); // color mode
            }

            if (cap & 0x0004)
            {
                toCheck.push_back(0x4002); // Color loop active
            }

            if (cap & 0x0008)
            {
                toCheck.push_back(0x0003); // currentX
                toCheck.push_back(0x0004); // currentY
            }

            if (cap & 0x0010)
            {
                toCheck.push_back(0x0007); // color temperature
            }

            for (const deCONZ::ZclCluster &cl : lightNode->haEndpoint().inClusters())
            {
                if (cl.id() != COLOR_CLUSTER_ID)
                {
                    continue;
                }

                for (const deCONZ::ZclAttribute &attr : cl.attributes())
                {
                    for (quint16 attrId : toCheck)
                    {
                        // discard attributes which are not be available
                        if (attrId == attr.id() && attr.isAvailable())
                        {
                            NodeValue &val = restNode->getZclValue(clusterId, attrId);
                            if (isOn || !val.timestamp.isValid())
                            {
                                attributes.push_back(attrId);
                            }
                        }
                    }
                }

                break;
            }
        }
    }
    else if (suffix == RStateConsumption)
    {
        clusterId = METERING_CLUSTER_ID;
        attributes.push_back(0x0000); // Curent Summation Delivered
        attributes.push_back(0x0400); // Instantaneous Demand
    }
    else if (suffix == RStatePower)
    {
        clusterId = ELECTRICAL_MEASUREMENT_CLUSTER_ID;
        attributes.push_back(0x050b); // Active Power
        item = r->item(RAttrModelId);
        if (! item->toString().startsWith(QLatin1String("Plug"))) // OSRAM plug
        {
            attributes.push_back(0x0505); // RMS Voltage
            attributes.push_back(0x0508); // RMS Current
        }
    }
    else if (suffix == RAttrModelId)
    {
        item = r->item(RAttrModelId);
        if (item && (item->toString().isEmpty() || item->toString() == QLatin1String("unknown") ||
             (item->lastSet().secsTo(now) > READ_MODEL_ID_INTERVAL && item->toString().startsWith("FLS-A")) // dynamic model ids
            ))
        {
            clusterId = BASIC_CLUSTER_ID;
            //attributes.push_back(0x0004); // manufacturer
            attributes.push_back(0x0005); // model id
        }
    }

    size_t fresh = 0;
    for (quint16 attrId : attributes)
    {
        NodeValue &val = restNode->getZclValue(clusterId, attrId);

        if (val.timestampLastReport.isValid() && val.timestampLastReport.secsTo(now) < 360)
        {
            fresh++;
        }
    }

    if (clusterId && fresh > 0 && fresh == attributes.size())
    {
        DBG_Printf(DBG_INFO, "Poll APS request to 0x%016llX cluster: 0x%04X dropped, values are fresh enough\n", pitem.address.ext(), clusterId);
        suffix = 0; // clear
        timer->start(100);
    }
    else if (!attributes.empty() && clusterId &&
        plugin->readAttributes(restNode, pitem.endpoint, clusterId, attributes))
    {
        pollState = StateWait;
        // TODO this hack to get aps request id
        DBG_Assert(plugin->tasks.back().taskType == TaskReadAttributes);
        apsReqId = plugin->tasks.back().req.id();
        dstAddr = pitem.address;
        timer->start(20 * 1000); // wait for confirm
        suffix = 0; // clear
        DBG_Printf(DBG_INFO_L2, "Poll APS request %u to 0x%016llX cluster: 0x%04X\n", apsReqId, dstAddr.ext(), clusterId);
    }
    else if (suffix)
    {
        suffix = 0; // clear
        timer->start(100);
    }
    else
    {
        if (clusterId)
        {
            DBG_Printf(DBG_INFO, "Poll APS request to 0x%016llX cluster: 0x%04X dropped\n", pitem.address.ext(), clusterId);
        }
        timer->start(100);
        items.front() = items.back();
        items.pop_back();
    }

}
<commit_msg>Poll manager: support ZHALightLevel and ZHAPresence for mains powered sensors<commit_after>/*
 * Copyright (c) 2017 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include "poll_manager.h"
#include "de_web_plugin_private.h"

/*! Constructor.
 */
PollManager::PollManager(QObject *parent) :
    QObject(parent)
{
    pollState = StateIdle;
    timer = new QTimer(this);
    timer->setSingleShot(true);
    connect(timer, SIGNAL(timeout()), this, SLOT(pollTimerFired()));
    plugin = qobject_cast<DeRestPluginPrivate*>(parent);
}

/*! Queues polling of the node.
    \param restNode - the node to poll
 */
void PollManager::poll(RestNodeBase *restNode, const QDateTime &tStart)
{
    Resource *r = dynamic_cast<Resource*>(restNode);
    DBG_Assert(r != 0);
    if (!r || !restNode->node())
    {
        return;
    }

    PollItem pitem;

    if (!restNode->node()->nodeDescriptor().receiverOnWhenIdle())
    {
        return;
    }

    LightNode *lightNode = 0;
    Sensor *sensor = 0;

    if (r->prefix() == RLights)
    {
        lightNode = static_cast<LightNode*>(restNode);
        DBG_Assert(lightNode != 0);
        pitem.endpoint = lightNode->haEndpoint().endpoint();
        DBG_Printf(DBG_INFO_L2, ">>>> Poll light node %s\n", qPrintable(lightNode->name()));
    }
    else if (r->prefix() == RSensors)
    {
        sensor = static_cast<Sensor*>(restNode);
        DBG_Assert(sensor != 0);
        pitem.endpoint = sensor->fingerPrint().endpoint;
        DBG_Printf(DBG_INFO_L2, ">>>> Poll %s sensor node %s\n", qPrintable(sensor->type()), qPrintable(sensor->name()));
    }
    else
    {
        return;
    }

    pitem.id = restNode->id();
    pitem.prefix = r->prefix();
    pitem.address = restNode->address();
    pitem.tStart = tStart;

    for (int i = 0; i < r->itemCount(); i++)
    {
        const ResourceItem *item = r->itemForIndex(i);
        const char *suffix = item ? item->descriptor().suffix : 0;

        if (suffix == RStateOn ||
            suffix == RStateBri ||
            suffix == RStateColorMode ||
            (suffix == RStateConsumption && sensor && sensor->type() == QLatin1String("ZHAConsumption")) ||
            (suffix == RStatePower && sensor && sensor->type() == QLatin1String("ZHAPower")) ||
            (suffix == RStatePresence && sensor && sensor->type() == QLatin1String("ZHAPresence")) ||
            (suffix == RStateLightLevel && sensor && sensor->type() == QLatin1String("ZHALightLevel")) ||
            suffix == RAttrModelId)
        {
            // DBG_Printf(DBG_INFO_L2, "    attribute %s\n", suffix);
            pitem.items.push_back(suffix);
        }
    }

    for (PollItem &i : items)
    {
        if (i.prefix == r->prefix() && i.id == restNode->id())
        {
            i.items = pitem.items; // update
            if (tStart.isValid())
            {
                i.tStart = tStart;
            }
            return;
        }
    }

    items.push_back(pitem);

    if (!timer->isActive())
    {
        timer->start(1);
    }
}

/*! Delays polling for \p ms milliseconds.
 */
void PollManager::delay(int ms)
{
    timer->stop();
    timer->start(ms);
}

/*! Handle APS confirm if related to polling.
 */
void PollManager::apsdeDataConfirm(const deCONZ::ApsDataConfirm &conf)
{
    if (pollState != StateWait)
    {
        return;
    }

    if (apsReqId != conf.id())
    {
        return;
    }

    if (dstAddr.hasExt() && conf.dstAddress().hasExt()
        && dstAddr.ext() != conf.dstAddress().ext())
    {

    }

    else if (dstAddr.hasNwk() && conf.dstAddress().hasNwk()
        && dstAddr.nwk() != conf.dstAddress().nwk())
    {

    }

    DBG_Printf(DBG_INFO_L2, "Poll APS confirm %u status: 0x%02X\n", conf.id(), conf.status());

    pollState = StateIdle;
    timer->stop();
    timer->start(1);
}

/*! Timer callback to proceed polling.
 */
void PollManager::pollTimerFired()
{
    if (pollState == StateWait)
    {
        DBG_Printf(DBG_INFO, "timout on poll APS confirm\n");
        pollState = StateIdle;
    }

    DBG_Assert(pollState == StateIdle);

    if (items.empty())
    {
        plugin->pollNextLight();
        return;
    }

    QDateTime now = QDateTime::currentDateTime();
    PollItem &pitem = items.front();
    Resource *r = plugin->getResource(pitem.prefix, pitem.id);
    ResourceItem *item = 0;
    RestNodeBase *restNode = 0;
    const LightNode *lightNode = 0;
    if (r && r->prefix() == RLights)
    {
        restNode = plugin->getLightNodeForId(pitem.id);
        lightNode = static_cast<LightNode*>(restNode);
        item = r->item(RStateReachable);
    }
    else if (r && r->prefix() == RSensors)
    {
        restNode = plugin->getSensorNodeForId(pitem.id);
        item = r->item(RConfigReachable);
    }

    if (pitem.tStart.isValid() && pitem.tStart > now)
    {
        if (items.size() > 1)
        {
            PollItem tmp = pitem;
            items.front() = items.back();
            items.back() = tmp;
        }
        timer->start(1);
        return;
    }

    if (!r || pitem.items.empty() ||
        !restNode ||
        //!restNode->lastRx().isValid() ||
        !item || !item->toBool()) // not reachable
    {
        items.front() = items.back();
        items.pop_back();
        timer->start(1);
        return;
    }

    quint16 clusterId = 0;
    std::vector<quint16> attributes;

    item = r->item(RStateOn);
    bool isOn = item ? item->toBool() : false;
    const char *&suffix = pitem.items[0];

    for (size_t i = 0; pitem.items[0] == 0 && i < pitem.items.size(); i++)
    {
        if (pitem.items[i] != 0)
        {
            pitem.items[0] = pitem.items[i]; // move to front
            pitem.items[i] = 0; // clear
            break;
        }
    }

    if (!suffix)
    {
        pitem.items.clear(); // all done
    }

    if (suffix == RStateOn)
    {
        clusterId = ONOFF_CLUSTER_ID;
        attributes.push_back(0x0000); // onOff
    }
    else if (suffix == RStateBri && isOn)
    {
        NodeValue &val = restNode->getZclValue(LEVEL_CLUSTER_ID, 0x0000);

        if (isOn || !val.timestamp.isValid())
        {
            clusterId = LEVEL_CLUSTER_ID;
            attributes.push_back(0x0000); // current level
        }
    }
    else if (suffix == RStateColorMode && lightNode)
    {
        clusterId = COLOR_CLUSTER_ID;
        item = r->item(RConfigColorCapabilities);

        if (!item)
        {
            attributes.push_back(0x0008); // color mode
            attributes.push_back(0x4001); // enhanced color mode
            attributes.push_back(0x400a); // color capabilities
            attributes.push_back(0x400b); // color temperature min
            attributes.push_back(0x400c); // color temperature max
        }
        else
        {
            quint16 cap = item->toNumber();
            std::vector<quint16> toCheck;
            if (cap & 0x0002) // enhanced hue supported
            {
                toCheck.push_back(0x4001); // enhanced color mode
                toCheck.push_back(0x4000); // enhanced hue
                toCheck.push_back(0x0001); // saturation
            }
            else if (cap & 0x0001)
            {
                toCheck.push_back(0x0000); // hue
                toCheck.push_back(0x0001); // saturation
                toCheck.push_back(0x0008); // color mode
            }
            else
            {
                toCheck.push_back(0x0008); // color mode
            }

            if (cap & 0x0004)
            {
                toCheck.push_back(0x4002); // Color loop active
            }

            if (cap & 0x0008)
            {
                toCheck.push_back(0x0003); // currentX
                toCheck.push_back(0x0004); // currentY
            }

            if (cap & 0x0010)
            {
                toCheck.push_back(0x0007); // color temperature
            }

            for (const deCONZ::ZclCluster &cl : lightNode->haEndpoint().inClusters())
            {
                if (cl.id() != COLOR_CLUSTER_ID)
                {
                    continue;
                }

                for (const deCONZ::ZclAttribute &attr : cl.attributes())
                {
                    for (quint16 attrId : toCheck)
                    {
                        // discard attributes which are not be available
                        if (attrId == attr.id() && attr.isAvailable())
                        {
                            NodeValue &val = restNode->getZclValue(clusterId, attrId);
                            if (isOn || !val.timestamp.isValid())
                            {
                                attributes.push_back(attrId);
                            }
                        }
                    }
                }

                break;
            }
        }
    }
    else if (suffix == RStatePresence)
    {
        clusterId = OCCUPANCY_SENSING_CLUSTER_ID;
        attributes.push_back(0x0000); // Occupancy
        attributes.push_back(0x0010); // PIR Occupied To Unoccupied Delay
    }
    else if (suffix == RStateLightLevel)
    {
        clusterId = ILLUMINANCE_MEASUREMENT_CLUSTER_ID;
        attributes.push_back(0x0000); // Measured Value
    }
    else if (suffix == RStateConsumption)
    {
        clusterId = METERING_CLUSTER_ID;
        attributes.push_back(0x0000); // Curent Summation Delivered
        attributes.push_back(0x0400); // Instantaneous Demand
    }
    else if (suffix == RStatePower)
    {
        clusterId = ELECTRICAL_MEASUREMENT_CLUSTER_ID;
        attributes.push_back(0x050b); // Active Power
        item = r->item(RAttrModelId);
        if (! item->toString().startsWith(QLatin1String("Plug"))) // OSRAM plug
        {
            attributes.push_back(0x0505); // RMS Voltage
            attributes.push_back(0x0508); // RMS Current
        }
    }
    else if (suffix == RAttrModelId)
    {
        item = r->item(RAttrModelId);
        if (item && (item->toString().isEmpty() || item->toString() == QLatin1String("unknown") ||
             (item->lastSet().secsTo(now) > READ_MODEL_ID_INTERVAL && item->toString().startsWith("FLS-A")) // dynamic model ids
            ))
        {
            clusterId = BASIC_CLUSTER_ID;
            //attributes.push_back(0x0004); // manufacturer
            attributes.push_back(0x0005); // model id
        }
    }

    size_t fresh = 0;
    for (quint16 attrId : attributes)
    {
        NodeValue &val = restNode->getZclValue(clusterId, attrId);

        if (val.timestampLastReport.isValid() && val.timestampLastReport.secsTo(now) < 360)
        {
            fresh++;
        }
    }

    if (clusterId && fresh > 0 && fresh == attributes.size())
    {
        DBG_Printf(DBG_INFO, "Poll APS request to 0x%016llX cluster: 0x%04X dropped, values are fresh enough\n", pitem.address.ext(), clusterId);
        suffix = 0; // clear
        timer->start(100);
    }
    else if (!attributes.empty() && clusterId &&
        plugin->readAttributes(restNode, pitem.endpoint, clusterId, attributes))
    {
        pollState = StateWait;
        // TODO this hack to get aps request id
        DBG_Assert(plugin->tasks.back().taskType == TaskReadAttributes);
        apsReqId = plugin->tasks.back().req.id();
        dstAddr = pitem.address;
        timer->start(20 * 1000); // wait for confirm
        suffix = 0; // clear
        DBG_Printf(DBG_INFO_L2, "Poll APS request %u to 0x%016llX cluster: 0x%04X\n", apsReqId, dstAddr.ext(), clusterId);
    }
    else if (suffix)
    {
        suffix = 0; // clear
        timer->start(100);
    }
    else
    {
        if (clusterId)
        {
            DBG_Printf(DBG_INFO, "Poll APS request to 0x%016llX cluster: 0x%04X dropped\n", pitem.address.ext(), clusterId);
        }
        timer->start(100);
        items.front() = items.back();
        items.pop_back();
    }

}
<|endoftext|>


<commit_before>/*******************************************************************************
 * tests/net/group_test.cpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <c7a/net/group.hpp>
#include <c7a/net/flow_control_channel.hpp>
#include <c7a/net/dispatcher.hpp>
#include <c7a/net/manager.hpp>
#include <c7a/net/collective_communication.hpp>
#include <gtest/gtest.h>

#include <thread>
#include <vector>
#include <string>
#include <random>

using namespace c7a::net;

static void ThreadInitializeAsyncRead(Group* net) {
    // send a message to all other clients except ourselves.
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        net->connection(i).GetSocket().send(&i, sizeof(size_t));
    }

    size_t received = 0;
    Dispatcher dispatcher;

    Dispatcher::AsyncReadCallback callback =
        [net, &received](Connection& /* s */, const Buffer& buffer) {
            ASSERT_EQ(*(reinterpret_cast<const size_t*>(buffer.data())),
                      net->MyRank());
            received++;
        };

    // add async reads to net dispatcher
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        dispatcher.AsyncRead(net->connection(i), sizeof(size_t), callback);
    }

    while (received < net->Size() - 1) {
        dispatcher.Dispatch();
    }
}

static void ThreadInitializeBroadcastIntegral(Group* net) {

    static const bool debug = false;

    //Broadcast our ID to everyone
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        net->SendTo(i, net->MyRank());
    }

    //Receive the id from everyone. Make sure that the id is correct.
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;

        size_t val;
        ClientId id;

        net->ReceiveFromAny<size_t>(&id, &val);

        LOG << "Received " << val << " from " << id;

        ASSERT_EQ((int)id, (int)val);
    }
}

static void ThreadInitializeSendReceive(Group* net) {
    static const bool debug = false;

    // send a message to all other clients except ourselves.
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        net->SendStringTo(i, "Hello " + std::to_string(net->MyRank())
                          + " -> " + std::to_string(i));
    }
    // receive the n-1 messages from clients in order
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;

        std::string msg;
        net->ReceiveStringFrom(i, &msg);
        sLOG << "Received from client" << i << "msg" << msg;

        ASSERT_EQ(msg, "Hello " + std::to_string(i)
                  + " -> " + std::to_string(net->MyRank()));
    }

    // *****************************************************************

    // send another message to all other clients except ourselves. Now with connection access.
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        net->connection(i).SendString("Hello " + std::to_string(net->MyRank())
                                      + " -> " + std::to_string(i));
    }
    // receive the n-1 messages from clients in any order
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;

        ClientId from;
        std::string msg;
        net->ReceiveStringFromAny(&from, &msg);
        sLOG << "Received from client" << i << "msg" << msg;

        ASSERT_EQ(msg, "Hello " + std::to_string(from)
                  + " -> " + std::to_string(net->MyRank()));
    }
}

static void ThreadInitializeSendReceiveALot(Group* net) {
    for (int i = 0; i < 100; i++) {
        ThreadInitializeSendReceive(net);
    }
}

static void ThreadInitializeSendReceiveAsyncALot(Group* net) {
    for (int i = 0; i < 100; i++) {
        ThreadInitializeAsyncRead(net);
    }
}

static void RealGroupConstructAndCall(
    std::function<void(Group*)> thread_function) {
    // randomize base port number for test
    std::random_device random_device;
    std::default_random_engine generator(random_device());
    std::uniform_int_distribution<int> distribution(30000, 65000);
    const size_t port_base = distribution(generator);

    static const std::vector<Endpoint> endpoints = {
        Endpoint("127.0.0.1:" + std::to_string(port_base + 0)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 1)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 2)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 3)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 4)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 5))
    };

    sLOG1 << "Group test uses ports " << port_base << "-" << port_base + 5;

    static const int count = endpoints.size();

    std::vector<std::thread> threads(count);

    // lambda to construct Group and call user thread function.

    std::vector<Manager> groups(count);

    for (int i = 0; i < count; i++) {
        threads[i] = std::thread(
            [i, &thread_function, &groups]() {
                // construct Group i with endpoints
                groups[i].Initialize(i, endpoints);
                // run thread function
                thread_function(&groups[i].GetFlowGroup());
            });
    }

    for (int i = 0; i < count; i++) {
        threads[i].join();
    }
}

TEST(Group, RealInitializeAndClose) {
    // Construct a real Group of 6 workers which do nothing but terminate.
    RealGroupConstructAndCall([](Group*) { });
}

TEST(Group, RealInitializeSendReceive) {
    // Construct a real Group of 6 workers which execute the thread function
    // above which sends and receives a message from all neighbors.
    RealGroupConstructAndCall(ThreadInitializeSendReceive);
}

TEST(Group, RealInitializeSendReceiveALot) {
    // Construct a real Group of 6 workers which execute the thread function
    // above which sends and receives a message from all neighbors.
    RealGroupConstructAndCall(ThreadInitializeSendReceive);
}

TEST(Group, RealInitializeSendReceiveAsync) { //TODO(ej) test hangs from time to time
    // Construct a real Group of 6 workers which execute the thread function
    // which sends and receives asynchronous messages between all workers.
    RealGroupConstructAndCall(ThreadInitializeAsyncRead);
}

TEST(Group, RealInitializeSendReceiveAsyncALot) {
    // Construct a real Group of 6 workers which execute the thread function
    // above which sends and receives a message from all neighbors.
    RealGroupConstructAndCall(ThreadInitializeSendReceive);
}

TEST(Group, RealInitializeBroadcast) {
    // Construct a real Group of 6 workers which execute the thread function
    // above which sends and receives a message from all workers.
    RealGroupConstructAndCall(ThreadInitializeBroadcastIntegral);
}

TEST(Group, InitializeAndClose) {
    // Construct a Group of 6 workers which do nothing but terminate.
    Group::ExecuteLocalMock(6, [](Group*) { });
}

TEST(Manager, InitializeAndClose) {
    // Construct a Group of 6 workers which do nothing but terminate.
    Manager::ExecuteLocalMock(6, [](Group*) { }, [](Group*) { }, [](Group*) { });
}

TEST(Group, InitializeSendReceive) {
    // Construct a Group of 6 workers which execute the thread function
    // which sends and receives asynchronous messages between all workers.
    Group::ExecuteLocalMock(6, ThreadInitializeSendReceive);
}

TEST(Group, InitializeBroadcast) {
    // Construct a Group of 6 workers which execute the thread function
    // above which sends and receives a message from all workers.
    Group::ExecuteLocalMock(6, ThreadInitializeBroadcastIntegral);
}

/*
TEST(Group, TestPrefixSum) {
    for (size_t p = 2; p <= 8; p *= 2) {
        // Construct Group of p workers which perform a PrefixSum collective
        Group::ExecuteLocalMock(
            p, [](Group* net) {
                size_t local_value = 1;
                net->PrefixSum(local_value);
                ASSERT_EQ(local_value, net->MyRank() + 1);
            });
    }
}
*/

TEST(Group, TestAllReduce) {
    for (size_t p = 0; p <= 8; ++p) {
        // Construct Group of p workers which perform an AllReduce collective
        Group::ExecuteLocalMock(
            p, [](Group* net) {
                size_t local_value = net->MyRank();
                c7a::net::AllReduce(*net, local_value);
                ASSERT_EQ(local_value, net->Size() * (net->Size() - 1) / 2);
            });
    }
}

TEST(Group, TestBroadcast) {
    for (size_t p = 0; p <= 8; ++p) {
        // Construct Group of p workers which perform an Broadcast collective
        Group::ExecuteLocalMock(
            p, [](Group* net) {
                size_t local_value;
                if (net->MyRank() == 0) local_value = 42;
                c7a::net::Broadcast(*net, local_value);
                ASSERT_EQ(local_value, 42u);
            });
    }
}

TEST(Group, TestReduceToRoot) {
    for (size_t p = 0; p <= 8; ++p) {
        // Construct Group of p workers which perform an Broadcast collective
        Group::ExecuteLocalMock(
            p, [](Group* net) {
                size_t local_value = net->MyRank();
                c7a::net::ReduceToRoot(*net, local_value);
                if (net->MyRank() == 0)
                    ASSERT_EQ(local_value, net->Size() * (net->Size() - 1) / 2);
            });
    }
}

TEST(Group, TestBarrier) {
    static const bool debug = false;
    std::mutex sync_mtx; // Synchronisation mutex for the barrier
    std::mutex local_mtx; // Mutex for writing to the results array
    std::condition_variable cv; // Condition variable for the barrier

    for (size_t p = 0; p <= 8; ++p) {
        int workers = p;
        int workers_copy = workers; // Will be decremented by the barrier function

        char result[2 * workers];
        int k = 0; // The counter for the result array
        sLOG << "I'm in test" << workers;

        Group::ExecuteLocalMock(
            workers, [&](Group* net) {
                local_mtx.lock();
                result[k++] = 'B'; // B stands for 'Before barrier'
                local_mtx.unlock();

                sLOG << "Before Barrier, worker" << net->MyRank();

                c7a::net::ThreadBarrier(sync_mtx, cv, workers_copy);

                local_mtx.lock();
                result[k++] = 'A'; // A stands for 'After barrier'
                local_mtx.unlock();

                sLOG << "After Barrier, worker" << net->MyRank();
                });
        for (int i = 0; i < workers; ++i) {
            sLOG << "Checking position" << i;
            ASSERT_EQ(result[i], 'B');
        }
        for (int i = workers; i < 2 * workers; ++i) {
            sLOG << "Checking position" << i;
            ASSERT_EQ(result[i], 'A');
        }
    }
}

/******************************************************************************/
<commit_msg>Maybe fixing jenkins.<commit_after>/*******************************************************************************
 * tests/net/group_test.cpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <c7a/net/group.hpp>
#include <c7a/net/flow_control_channel.hpp>
#include <c7a/net/dispatcher.hpp>
#include <c7a/net/manager.hpp>
#include <c7a/net/collective_communication.hpp>
#include <gtest/gtest.h>

#include <thread>
#include <vector>
#include <string>
#include <random>

using namespace c7a::net;

static void ThreadInitializeAsyncRead(Group* net) {
    // send a message to all other clients except ourselves.
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        net->connection(i).GetSocket().send(&i, sizeof(size_t));
    }

    size_t received = 0;
    Dispatcher dispatcher;

    Dispatcher::AsyncReadCallback callback =
        [net, &received](Connection& /* s */, const Buffer& buffer) {
            ASSERT_EQ(*(reinterpret_cast<const size_t*>(buffer.data())),
                      net->MyRank());
            received++;
        };

    // add async reads to net dispatcher
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        dispatcher.AsyncRead(net->connection(i), sizeof(size_t), callback);
    }

    while (received < net->Size() - 1) {
        dispatcher.Dispatch();
    }
}

static void ThreadInitializeBroadcastIntegral(Group* net) {

    static const bool debug = false;

    //Broadcast our ID to everyone
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        net->SendTo(i, net->MyRank());
    }

    //Receive the id from everyone. Make sure that the id is correct.
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;

        size_t val;
        ClientId id;

        net->ReceiveFromAny<size_t>(&id, &val);

        LOG << "Received " << val << " from " << id;

        ASSERT_EQ((int)id, (int)val);
    }
}

static void ThreadInitializeSendReceive(Group* net) {
    static const bool debug = false;

    // send a message to all other clients except ourselves.
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        net->SendStringTo(i, "Hello " + std::to_string(net->MyRank())
                          + " -> " + std::to_string(i));
    }
    // receive the n-1 messages from clients in order
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;

        std::string msg;
        net->ReceiveStringFrom(i, &msg);
        sLOG << "Received from client" << i << "msg" << msg;

        ASSERT_EQ(msg, "Hello " + std::to_string(i)
                  + " -> " + std::to_string(net->MyRank()));
    }

    // *****************************************************************

    // send another message to all other clients except ourselves. Now with connection access.
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;
        net->connection(i).SendString("Hello " + std::to_string(net->MyRank())
                                      + " -> " + std::to_string(i));
    }
    // receive the n-1 messages from clients in any order
    for (size_t i = 0; i != net->Size(); ++i)
    {
        if (i == net->MyRank()) continue;

        ClientId from;
        std::string msg;
        net->ReceiveStringFromAny(&from, &msg);
        sLOG << "Received from client" << i << "msg" << msg;

        ASSERT_EQ(msg, "Hello " + std::to_string(from)
                  + " -> " + std::to_string(net->MyRank()));
    }
}

static void ThreadInitializeSendReceiveALot(Group* net) {
    for (int i = 0; i < 100; i++) {
        ThreadInitializeSendReceive(net);
    }
}

static void ThreadInitializeSendReceiveAsyncALot(Group* net) {
    for (int i = 0; i < 100; i++) {
        ThreadInitializeAsyncRead(net);
    }
}

static void RealGroupConstructAndCall(
    std::function<void(Group*)> thread_function) {
    // randomize base port number for test
    std::random_device random_device;
    std::default_random_engine generator(random_device());
    std::uniform_int_distribution<int> distribution(30000, 65000);
    const size_t port_base = distribution(generator);

    static const std::vector<Endpoint> endpoints = {
        Endpoint("127.0.0.1:" + std::to_string(port_base + 0)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 1)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 2)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 3)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 4)),
        Endpoint("127.0.0.1:" + std::to_string(port_base + 5))
    };

    sLOG1 << "Group test uses ports " << port_base << "-" << port_base + 5;

    static const int count = endpoints.size();

    std::vector<std::thread> threads(count);

    // lambda to construct Group and call user thread function.

    std::vector<Manager> groups(count);

    for (int i = 0; i < count; i++) {
        threads[i] = std::thread(
            [i, &thread_function, &groups]() {
                // construct Group i with endpoints
                groups[i].Initialize(i, endpoints);
                // run thread function
                thread_function(&groups[i].GetFlowGroup());
            });
    }

    for (int i = 0; i < count; i++) {
        threads[i].join();
    }
}

TEST(Group, RealInitializeAndClose) {
    // Construct a real Group of 6 workers which do nothing but terminate.
    RealGroupConstructAndCall([](Group*) { });
}

TEST(Group, RealInitializeSendReceive) {
    // Construct a real Group of 6 workers which execute the thread function
    // above which sends and receives a message from all neighbors.
    RealGroupConstructAndCall(ThreadInitializeSendReceive);
}

TEST(Group, RealInitializeSendReceiveALot) {
    // Construct a real Group of 6 workers which execute the thread function
    // above which sends and receives a message from all neighbors.
    RealGroupConstructAndCall(ThreadInitializeSendReceive);
}

TEST(Group, RealInitializeSendReceiveAsync) { //TODO(ej) test hangs from time to time
    // Construct a real Group of 6 workers which execute the thread function
    // which sends and receives asynchronous messages between all workers.
    RealGroupConstructAndCall(ThreadInitializeAsyncRead);
}

TEST(Group, RealInitializeSendReceiveAsyncALot) {
    // Construct a real Group of 6 workers which execute the thread function
    // above which sends and receives a message from all neighbors.
    RealGroupConstructAndCall(ThreadInitializeSendReceive);
}

TEST(Group, RealInitializeBroadcast) {
    // Construct a real Group of 6 workers which execute the thread function
    // above which sends and receives a message from all workers.
    RealGroupConstructAndCall(ThreadInitializeBroadcastIntegral);
}

TEST(Group, InitializeAndClose) {
    // Construct a Group of 6 workers which do nothing but terminate.
    Group::ExecuteLocalMock(6, [](Group*) { });
}

TEST(Manager, InitializeAndClose) {
    // Construct a Group of 6 workers which do nothing but terminate.
    Manager::ExecuteLocalMock(6, [](Group*) { }, [](Group*) { }, [](Group*) { });
}

TEST(Group, InitializeSendReceive) {
    // Construct a Group of 6 workers which execute the thread function
    // which sends and receives asynchronous messages between all workers.
    Group::ExecuteLocalMock(6, ThreadInitializeSendReceive);
}

TEST(Group, InitializeBroadcast) {
    // Construct a Group of 6 workers which execute the thread function
    // above which sends and receives a message from all workers.
    Group::ExecuteLocalMock(6, ThreadInitializeBroadcastIntegral);
}

/*
TEST(Group, TestPrefixSum) {
    for (size_t p = 2; p <= 8; p *= 2) {
        // Construct Group of p workers which perform a PrefixSum collective
        Group::ExecuteLocalMock(
            p, [](Group* net) {
                size_t local_value = 1;
                net->PrefixSum(local_value);
                ASSERT_EQ(local_value, net->MyRank() + 1);
            });
    }
}
*/

TEST(Group, TestAllReduce) {
    for (size_t p = 0; p <= 8; ++p) {
        // Construct Group of p workers which perform an AllReduce collective
        Group::ExecuteLocalMock(
            p, [](Group* net) {
                size_t local_value = net->MyRank();
                c7a::net::AllReduce(*net, local_value);
                ASSERT_EQ(local_value, net->Size() * (net->Size() - 1) / 2);
            });
    }
}

TEST(Group, TestBroadcast) {
    for (size_t p = 0; p <= 8; ++p) {
        // Construct Group of p workers which perform an Broadcast collective
        Group::ExecuteLocalMock(
            p, [](Group* net) {
                size_t local_value;
                if (net->MyRank() == 0) local_value = 42;
                c7a::net::Broadcast(*net, local_value);
                ASSERT_EQ(local_value, 42u);
            });
    }
}

TEST(Group, TestReduceToRoot) {
    for (size_t p = 0; p <= 8; ++p) {
        // Construct Group of p workers which perform an Broadcast collective
        Group::ExecuteLocalMock(
            p, [](Group* net) {
                size_t local_value = net->MyRank();
                c7a::net::ReduceToRoot(*net, local_value);
                if (net->MyRank() == 0)
                    ASSERT_EQ(local_value, net->Size() * (net->Size() - 1) / 2);
            });
    }
}

TEST(Group, TestBarrier) {
    static const bool debug = false;
    std::mutex sync_mtx; // Synchronisation mutex for the barrier
    std::mutex local_mtx; // Mutex for writing to the results array
    std::condition_variable cv; // Condition variable for the barrier

    for (size_t p = 0; p <= 8; ++p) {
        int workers = p;
        int workers_copy = workers; // Will be decremented by the barrier function

        std::vector<char> result(2 * workers);
        int k = 0; // The counter for the result array
        sLOG << "I'm in test" << workers;

        Group::ExecuteLocalMock(
            workers, [&](Group* net) {
                local_mtx.lock();
                result[k++] = 'B'; // B stands for 'Before barrier'
                local_mtx.unlock();

                sLOG << "Before Barrier, worker" << net->MyRank();

                c7a::net::ThreadBarrier(sync_mtx, cv, workers_copy);

                local_mtx.lock();
                result[k++] = 'A'; // A stands for 'After barrier'
                local_mtx.unlock();

                sLOG << "After Barrier, worker" << net->MyRank();
                });
        for (int i = 0; i < workers; ++i) {
            sLOG << "Checking position" << i;
            ASSERT_EQ(result[i], 'B');
        }
        for (int i = workers; i < 2 * workers; ++i) {
            sLOG << "Checking position" << i;
            ASSERT_EQ(result[i], 'A');
        }
    }
}

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


<commit_before>
/*
 * Copyright 2013 The Servo Project Developers
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gl/SkNativeSharedGLContext.h"
#include "gl/GrGLUtil.h"

SkNativeSharedGLContext::SkNativeSharedGLContext(GrGLSharedContext sharedContext)
    : fContext(NULL)
    , fGrContext(NULL)
    , fGL(NULL)
    , fSharedContext(sharedContext)
    , fFBO(0)
    , fTextureID(0)
    , fDepthStencilBufferID(0) {

    fDisplay = XOpenDisplay(NULL);
    SkASSERT(NULL != fDisplay);
    int screen = DefaultScreen(fDisplay);
    GLint att[] = {
        GLX_RGBA,
        GLX_DEPTH_SIZE, 24,
        None
    };
    XVisualInfo *visinfo = glXChooseVisual(fDisplay, screen, att);
    Drawable root = RootWindow(fDisplay, screen);
    fPixmap = XCreatePixmap(fDisplay, root, 10, 10, visinfo->depth);
    fGlxPixmap = glXCreateGLXPixmap(fDisplay, visinfo, fPixmap);
}

SkNativeSharedGLContext::~SkNativeSharedGLContext() {
    if (fGL) {
        SK_GL_NOERRCHECK(*this, DeleteFramebuffers(1, &fFBO));
        SK_GL_NOERRCHECK(*this, DeleteTextures(1, &fTextureID));
        SK_GL_NOERRCHECK(*this, DeleteRenderbuffers(1, &fDepthStencilBufferID));
    }
    SkSafeUnref(fGL);
    this->destroyGLContext();
    glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
    XFreePixmap(fDisplay, fPixmap);
    if (fDisplay) XCloseDisplay(fDisplay);
    if (fGrContext) {
        fGrContext->Release();
    }
}

void SkNativeSharedGLContext::destroyGLContext() {
    if (NULL != fContext) {
        glXDestroyContext(fDisplay, fContext);
    }
}

const GrGLInterface* SkNativeSharedGLContext::createGLContext() {
    SkASSERT(NULL == fContext);

    XVisualInfo *visinfo;
    int screen = DefaultScreen(fDisplay);
    GLint att[] = {
        GLX_RGBA,
        GLX_DEPTH_SIZE, 24,
        None
    };

    visinfo = glXChooseVisual(fDisplay, screen, att);
    fContext = glXCreateContext(fDisplay, visinfo, fSharedContext, true);

    if (NULL == fContext) {
        SkDebugf("glXCreateContext failed with %d.", fContext);
        return NULL;
    }

    glXMakeCurrent(fDisplay, fGlxPixmap, fContext);

    const GrGLInterface* interface = GrGLCreateNativeInterface();
    if (NULL == interface) {
        SkDebugf("Context could not create GL interface.\n");
        this->destroyGLContext();
        return NULL;
    }

    return interface;
}

bool SkNativeSharedGLContext::init(const int width, const int height) {
    if (fGL) {
        fGL->unref();
        this->destroyGLContext();
    }

    fGL = this->createGLContext();
    if (fGL) {
        const GrGLubyte* temp;

        GrGLBinding bindingInUse = GrGLGetBindingInUse(this->gl());

        if (!fGL->validate(bindingInUse) || !fExtensions.init(bindingInUse, fGL)) {
            fGL = NULL;
            this->destroyGLContext();
            return false;
        }

        SK_GL_RET(*this, temp, GetString(GR_GL_VERSION));
        const char* versionStr = reinterpret_cast<const char*>(temp);
        GrGLVersion version = GrGLGetVersionFromString(versionStr);

        // clear any existing GL erorrs
        GrGLenum error;
        do {
            SK_GL_RET(*this, error, GetError());
        } while (GR_GL_NO_ERROR != error);

        SK_GL(*this, GenFramebuffers(1, &fFBO));
        SK_GL(*this, BindFramebuffer(GR_GL_FRAMEBUFFER, fFBO));
        SK_GL(*this, GenTextures(1, &fTextureID));
        SK_GL(*this, BindTexture(GR_GL_TEXTURE_2D, fTextureID));
        SK_GL(*this, TexImage2D(GR_GL_TEXTURE_2D, 0,
                                GR_GL_RGBA,
                                width, height, 0,
                                GR_GL_RGBA, GR_GL_UNSIGNED_BYTE,
                                NULL));
        SK_GL(*this, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE));
        SK_GL(*this, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE));
        SK_GL(*this, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST));
        SK_GL(*this, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST));
        SK_GL(*this, FramebufferTexture2D(GR_GL_FRAMEBUFFER,
                                          GR_GL_COLOR_ATTACHMENT0,
                                          GR_GL_TEXTURE_2D,
                                          fTextureID, 0));
        SK_GL(*this, GenRenderbuffers(1, &fDepthStencilBufferID));
        SK_GL(*this, BindRenderbuffer(GR_GL_RENDERBUFFER, fDepthStencilBufferID));

        // Some drivers that support packed depth stencil will only succeed
        // in binding a packed format an FBO. However, we can't rely on packed
        // depth stencil being available.
        bool supportsPackedDepthStencil;
        if (kES2_GrGLBinding == bindingInUse) {
            supportsPackedDepthStencil = this->hasExtension("GL_OES_packed_depth_stencil");
        } else {
            supportsPackedDepthStencil = version >= GR_GL_VER(3,0) ||
                                         this->hasExtension("GL_EXT_packed_depth_stencil") ||
                                         this->hasExtension("GL_ARB_framebuffer_object");
        }

        if (supportsPackedDepthStencil) {
            // ES2 requires sized internal formats for RenderbufferStorage
            // On Desktop we let the driver decide.
            GrGLenum format = kES2_GrGLBinding == bindingInUse ?
                                    GR_GL_DEPTH24_STENCIL8 :
                                    GR_GL_DEPTH_STENCIL;
            SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
                                             format,
                                             width, height));
            SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
                                                 GR_GL_DEPTH_ATTACHMENT,
                                                 GR_GL_RENDERBUFFER,
                                                 fDepthStencilBufferID));
        } else {
            GrGLenum format = kES2_GrGLBinding == bindingInUse ?
                                    GR_GL_STENCIL_INDEX8 :
                                    GR_GL_STENCIL_INDEX;
            SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
                                             format,
                                             width, height));
        }
        SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
                                             GR_GL_STENCIL_ATTACHMENT,
                                             GR_GL_RENDERBUFFER,
                                             fDepthStencilBufferID));
        SK_GL(*this, Viewport(0, 0, width, height));
        SK_GL(*this, ClearStencil(0));
        SK_GL(*this, Clear(GR_GL_STENCIL_BUFFER_BIT));

        SK_GL_RET(*this, error, GetError());
        GrGLenum status;
        SK_GL_RET(*this, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));

        if (GR_GL_FRAMEBUFFER_COMPLETE != status ||
            GR_GL_NO_ERROR != error) {
            fFBO = 0;
            fTextureID = 0;
            fDepthStencilBufferID = 0;
            fGL->unref();
            fGL = NULL;
            this->destroyGLContext();
            return false;
        } else {
            return true;
        }
    }
    return false;
}

GrContext *SkNativeSharedGLContext::getGrContext() {
    if (fGrContext) {
        return fGrContext;
    } else {
        GrBackendContext p3dctx = reinterpret_cast<GrBackendContext>(this->gl());
        fGrContext = GrContext::Create(kOpenGL_GrBackend, p3dctx);
        if (fGrContext == NULL) {
            return NULL;
        }
        fGrContext->AddRef();
        return fGrContext;
    }
}

void SkNativeSharedGLContext::makeCurrent() const {
    glXMakeCurrent(fDisplay, fGlxPixmap, fContext);
}

void SkNativeSharedGLContext::flush() const {
    this->makeCurrent();
    SK_GL(*this, Flush());
}
<commit_msg>Duplicate texture stealing code from mac for unix.<commit_after>
/*
 * Copyright 2013 The Servo Project Developers
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gl/SkNativeSharedGLContext.h"
#include "gl/GrGLUtil.h"

SkNativeSharedGLContext::SkNativeSharedGLContext(GrGLSharedContext sharedContext)
    : fContext(NULL)
    , fGrContext(NULL)
    , fGL(NULL)
    , fSharedContext(sharedContext)
    , fFBO(0)
    , fTextureID(0)
    , fDepthStencilBufferID(0) {

    fDisplay = XOpenDisplay(NULL);
    SkASSERT(NULL != fDisplay);
    int screen = DefaultScreen(fDisplay);
    GLint att[] = {
        GLX_RGBA,
        GLX_DEPTH_SIZE, 24,
        None
    };
    XVisualInfo *visinfo = glXChooseVisual(fDisplay, screen, att);
    Drawable root = RootWindow(fDisplay, screen);
    fPixmap = XCreatePixmap(fDisplay, root, 10, 10, visinfo->depth);
    fGlxPixmap = glXCreateGLXPixmap(fDisplay, visinfo, fPixmap);
}

SkNativeSharedGLContext::~SkNativeSharedGLContext() {
    if (fGL) {
        SK_GL_NOERRCHECK(*this, DeleteFramebuffers(1, &fFBO));
        SK_GL_NOERRCHECK(*this, DeleteTextures(1, &fTextureID));
        SK_GL_NOERRCHECK(*this, DeleteRenderbuffers(1, &fDepthStencilBufferID));
    }
    SkSafeUnref(fGL);
    this->destroyGLContext();
    glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
    XFreePixmap(fDisplay, fPixmap);
    if (fDisplay) XCloseDisplay(fDisplay);
    if (fGrContext) {
        fGrContext->Release();
    }
}

void SkNativeSharedGLContext::destroyGLContext() {
    if (NULL != fContext) {
        glXDestroyContext(fDisplay, fContext);
    }
}

const GrGLInterface* SkNativeSharedGLContext::createGLContext() {
    SkASSERT(NULL == fContext);

    XVisualInfo *visinfo;
    int screen = DefaultScreen(fDisplay);
    GLint att[] = {
        GLX_RGBA,
        GLX_DEPTH_SIZE, 24,
        None
    };

    visinfo = glXChooseVisual(fDisplay, screen, att);
    fContext = glXCreateContext(fDisplay, visinfo, fSharedContext, true);

    if (NULL == fContext) {
        SkDebugf("glXCreateContext failed with %d.", fContext);
        return NULL;
    }

    glXMakeCurrent(fDisplay, fGlxPixmap, fContext);

    const GrGLInterface* interface = GrGLCreateNativeInterface();
    if (NULL == interface) {
        SkDebugf("Context could not create GL interface.\n");
        this->destroyGLContext();
        return NULL;
    }

    return interface;
}

bool SkNativeSharedGLContext::init(const int width, const int height) {
    if (fGL) {
        fGL->unref();
        this->destroyGLContext();
    }

    fGL = this->createGLContext();
    if (fGL) {
        const GrGLubyte* temp;

        GrGLBinding bindingInUse = GrGLGetBindingInUse(this->gl());

        if (!fGL->validate(bindingInUse) || !fExtensions.init(bindingInUse, fGL)) {
            fGL = NULL;
            this->destroyGLContext();
            return false;
        }

        SK_GL_RET(*this, temp, GetString(GR_GL_VERSION));
        const char* versionStr = reinterpret_cast<const char*>(temp);
        GrGLVersion version = GrGLGetVersionFromString(versionStr);

        // clear any existing GL erorrs
        GrGLenum error;
        do {
            SK_GL_RET(*this, error, GetError());
        } while (GR_GL_NO_ERROR != error);

        SK_GL(*this, GenFramebuffers(1, &fFBO));
        SK_GL(*this, BindFramebuffer(GR_GL_FRAMEBUFFER, fFBO));
        SK_GL(*this, GenTextures(1, &fTextureID));
        SK_GL(*this, BindTexture(GR_GL_TEXTURE_2D, fTextureID));
        SK_GL(*this, TexImage2D(GR_GL_TEXTURE_2D, 0,
                                GR_GL_RGBA,
                                width, height, 0,
                                GR_GL_RGBA, GR_GL_UNSIGNED_BYTE,
                                NULL));
        SK_GL(*this, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE));
        SK_GL(*this, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE));
        SK_GL(*this, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST));
        SK_GL(*this, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST));
        SK_GL(*this, FramebufferTexture2D(GR_GL_FRAMEBUFFER,
                                          GR_GL_COLOR_ATTACHMENT0,
                                          GR_GL_TEXTURE_2D,
                                          fTextureID, 0));
        SK_GL(*this, GenRenderbuffers(1, &fDepthStencilBufferID));
        SK_GL(*this, BindRenderbuffer(GR_GL_RENDERBUFFER, fDepthStencilBufferID));

        // Some drivers that support packed depth stencil will only succeed
        // in binding a packed format an FBO. However, we can't rely on packed
        // depth stencil being available.
        bool supportsPackedDepthStencil;
        if (kES2_GrGLBinding == bindingInUse) {
            supportsPackedDepthStencil = this->hasExtension("GL_OES_packed_depth_stencil");
        } else {
            supportsPackedDepthStencil = version >= GR_GL_VER(3,0) ||
                                         this->hasExtension("GL_EXT_packed_depth_stencil") ||
                                         this->hasExtension("GL_ARB_framebuffer_object");
        }

        if (supportsPackedDepthStencil) {
            // ES2 requires sized internal formats for RenderbufferStorage
            // On Desktop we let the driver decide.
            GrGLenum format = kES2_GrGLBinding == bindingInUse ?
                                    GR_GL_DEPTH24_STENCIL8 :
                                    GR_GL_DEPTH_STENCIL;
            SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
                                             format,
                                             width, height));
            SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
                                                 GR_GL_DEPTH_ATTACHMENT,
                                                 GR_GL_RENDERBUFFER,
                                                 fDepthStencilBufferID));
        } else {
            GrGLenum format = kES2_GrGLBinding == bindingInUse ?
                                    GR_GL_STENCIL_INDEX8 :
                                    GR_GL_STENCIL_INDEX;
            SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
                                             format,
                                             width, height));
        }
        SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
                                             GR_GL_STENCIL_ATTACHMENT,
                                             GR_GL_RENDERBUFFER,
                                             fDepthStencilBufferID));
        SK_GL(*this, Viewport(0, 0, width, height));
        SK_GL(*this, ClearStencil(0));
        SK_GL(*this, Clear(GR_GL_STENCIL_BUFFER_BIT));

        SK_GL_RET(*this, error, GetError());
        GrGLenum status;
        SK_GL_RET(*this, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));

        if (GR_GL_FRAMEBUFFER_COMPLETE != status ||
            GR_GL_NO_ERROR != error) {
            fFBO = 0;
            fTextureID = 0;
            fDepthStencilBufferID = 0;
            fGL->unref();
            fGL = NULL;
            this->destroyGLContext();
            return false;
        } else {
            return true;
        }
    }
    return false;
}

GrContext *SkNativeSharedGLContext::getGrContext() {
    if (fGrContext) {
        return fGrContext;
    } else {
        GrBackendContext p3dctx = reinterpret_cast<GrBackendContext>(this->gl());
        fGrContext = GrContext::Create(kOpenGL_GrBackend, p3dctx);
        if (fGrContext == NULL) {
            return NULL;
        }
        fGrContext->AddRef();
        return fGrContext;
    }
}

GrGLuint SkNativeSharedGLContext::stealTextureID() {
    // Unbind the texture from the framebuffer.
    if (fGL && fFBO) {
        SK_GL(*this, BindFramebuffer(GR_GL_FRAMEBUFFER, fFBO));
        SK_GL(*this, FramebufferTexture2D(GR_GL_FRAMEBUFFER,
                                          GR_GL_COLOR_ATTACHMENT0,
                                          GR_GL_TEXTURE_2D,
                                          0,
                                          0));
    }

    GrGLuint textureID = fTextureID;
    fTextureID = 0;
    return textureID;
}

void SkNativeSharedGLContext::makeCurrent() const {
    glXMakeCurrent(fDisplay, fGlxPixmap, fContext);
}

void SkNativeSharedGLContext::flush() const {
    this->makeCurrent();
    SK_GL(*this, Flush());
}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2015 Anon authors, see AUTHORS file.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

#include "udp_dispatch.h"
#include <arpa/inet.h>
#include "fiber.h"

namespace {

sockaddr_storage clean_sockaddr(const sockaddr_storage& addr)
{
  sockaddr_storage clean;
  memset(&clean, 0, sizeof(clean));
  if (addr.ss_family == AF_INET)
  {
    ((sockaddr_in *)&clean)->sin_family = AF_INET;
    ((sockaddr_in *)&clean)->sin_addr = ((sockaddr_in *)&addr)->sin_addr;
    ((sockaddr_in *)&clean)->sin_port = ((sockaddr_in *)&addr)->sin_port;
  }
  else if (addr.ss_family == AF_INET6)
  {
    ((sockaddr_in6 *)&clean)->sin6_family = AF_INET6;
    ((sockaddr_in6 *)&clean)->sin6_addr = ((sockaddr_in6 *)&addr)->sin6_addr;
    ((sockaddr_in6 *)&clean)->sin6_port = ((sockaddr_in6 *)&addr)->sin6_port;
  }
  return clean;
}

}

udp_dispatch::udp_dispatch(int port_or_socket, bool is_socket, bool ipv6)
{
  // no SOCK_CLOEXEC since we inherit this socket down to the child
  // when we do a child swap
  int udd_port;
  if (is_socket) {
    sock_ = port_or_socket;
    struct sockaddr_in sin;
    socklen_t len = sizeof(sin);
    if (getsockname(sock_, (struct sockaddr *)&sin, &len) == -1)
      anon_throw(std::runtime_error, "getsockname(socket, (struct sockaddr *)&sin, &len) == -1, errno: " << errno_string());
    else
      port_num_ = ntohs(sin.sin_port);
  } else {
    port_num_ = port_or_socket;
    sock_ = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
    if (sock_ == -1)
      do_error("socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, 0)");

    // bind to any address that will route to this machine
    struct sockaddr_in6 addr = {0};
    socklen_t sz;
    if (ipv6)
    {
      addr.sin6_family = AF_INET6;
      addr.sin6_port = htons(port_or_socket);
      addr.sin6_addr = in6addr_any;
      sz = sizeof(sockaddr_in6);
    }
    else
    {
      auto addr4 = (struct sockaddr_in*)&addr;
      addr4->sin_family = AF_INET;
      addr4->sin_port = htons(port_or_socket);
      addr4->sin_addr.s_addr = INADDR_ANY;
      sz = sizeof(sockaddr_in);
    }
    if (bind(sock_, (struct sockaddr *)&addr, sz) != 0)
    {
      close(sock_);
      do_error("bind(<AF_INET/6 SOCK_DGRAM socket>, <" << port_or_socket << ", in6addr_any/INADDR_ANY>, sizeof(...))");
    }
  }

  anon_log("udp port " << port_num_ << " bound to socket " << sock_);

  io_dispatch::epoll_ctl(EPOLL_CTL_ADD, sock_, EPOLLIN, this);
}

void udp_dispatch::io_avail(const struct epoll_event &event)
{
  if (event.events & EPOLLIN)
  {
    while (true)
    {
      struct sockaddr_storage host;
      socklen_t host_addr_size = sizeof(host);
      auto buff = get_avail_buff();
      auto dlen = recvfrom(sock_, &(*buff)[0], buff->size(), 0, (struct sockaddr *)&host, &host_addr_size);
      if (dlen == -1)
      {
#if ANON_LOG_NET_TRAFFIC > 1
        if (errno != EAGAIN)
          anon_log("recvfrom failed with errno: " << errno_string());
#endif
        return;
      }
      else if (dlen == sizeof(buff->size()))
      {
#if ANON_LOG_NET_TRAFFIC > 1
        anon_log("message too big! all " << sizeof(msgBuff) << " bytes consumed in recvfrom call");
#endif
      }
      else
      {
        std::weak_ptr<udp_dispatch> wp = shared_from_this();
        fiber::run_in_fiber([wp, buff, dlen, host, host_addr_size] {
          auto ths = wp.lock();
          if (ths)
          {
            auto clean = clean_sockaddr(host);
            ths->recv_msg(&(*buff)[0], dlen, &clean, host_addr_size);
            ths->release_buff(buff);
          }
        });
      }
    }
  }
  else
    anon_log_error("udp_dispatch::io_avail called with no EPOLLIN. event.events = " << event_bits_to_string(event.events));
}

std::shared_ptr<std::vector<unsigned char>> udp_dispatch::get_avail_buff()
{
  std::unique_lock<std::mutex> l(mtx);
  if (free_buffs.size() > 0)
  {
    auto b = free_buffs.front();
    free_buffs.pop();
    return b;
  }
  return std::make_shared<std::vector<unsigned char>>(65536);
}

void udp_dispatch::release_buff(const std::shared_ptr<std::vector<unsigned char>>& buff)
{
  std::unique_lock<std::mutex> l(mtx);
  free_buffs.push(buff);
}
<commit_msg>bug fix<commit_after>/*
 Copyright (c) 2015 Anon authors, see AUTHORS file.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

#include "udp_dispatch.h"
#include <arpa/inet.h>
#include "fiber.h"

namespace {

sockaddr_storage clean_sockaddr(const sockaddr_storage& addr)
{
  sockaddr_storage clean;
  memset(&clean, 0, sizeof(clean));
  if (addr.ss_family == AF_INET)
  {
    ((sockaddr_in *)&clean)->sin_family = AF_INET;
    ((sockaddr_in *)&clean)->sin_addr = ((sockaddr_in *)&addr)->sin_addr;
    ((sockaddr_in *)&clean)->sin_port = ((sockaddr_in *)&addr)->sin_port;
  }
  else if (addr.ss_family == AF_INET6)
  {
    ((sockaddr_in6 *)&clean)->sin6_family = AF_INET6;
    ((sockaddr_in6 *)&clean)->sin6_addr = ((sockaddr_in6 *)&addr)->sin6_addr;
    ((sockaddr_in6 *)&clean)->sin6_port = ((sockaddr_in6 *)&addr)->sin6_port;
  }
  return clean;
}

}

udp_dispatch::udp_dispatch(int port_or_socket, bool is_socket, bool ipv6)
{
  // no SOCK_CLOEXEC since we inherit this socket down to the child
  // when we do a child swap
  int udd_port;
  if (is_socket) {
    sock_ = port_or_socket;
    struct sockaddr_in sin;
    socklen_t len = sizeof(sin);
    if (getsockname(sock_, (struct sockaddr *)&sin, &len) == -1)
      anon_throw(std::runtime_error, "getsockname(socket, (struct sockaddr *)&sin, &len) == -1, errno: " << errno_string());
    else
      port_num_ = ntohs(sin.sin_port);
  } else {
    port_num_ = port_or_socket;
    sock_ = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
    if (sock_ == -1)
      do_error("socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, 0)");

    // bind to any address that will route to this machine
    struct sockaddr_in6 addr = {0};
    socklen_t sz;
    if (ipv6)
    {
      addr.sin6_family = AF_INET6;
      addr.sin6_port = htons(port_or_socket);
      addr.sin6_addr = in6addr_any;
      sz = sizeof(sockaddr_in6);
    }
    else
    {
      auto addr4 = (struct sockaddr_in*)&addr;
      addr4->sin_family = AF_INET;
      addr4->sin_port = htons(port_or_socket);
      addr4->sin_addr.s_addr = INADDR_ANY;
      sz = sizeof(sockaddr_in);
    }
    if (bind(sock_, (struct sockaddr *)&addr, sz) != 0)
    {
      close(sock_);
      do_error("bind(<AF_INET/6 SOCK_DGRAM socket>, <" << port_or_socket << ", in6addr_any/INADDR_ANY>, sizeof(...))");
    }
  }

  anon_log("udp port " << port_num_ << " bound to socket " << sock_);

  io_dispatch::epoll_ctl(EPOLL_CTL_ADD, sock_, EPOLLIN, this);
}

void udp_dispatch::io_avail(const struct epoll_event &event)
{
  if (event.events & EPOLLIN)
  {
    while (true)
    {
      struct sockaddr_storage host;
      socklen_t host_addr_size = sizeof(host);
      auto buff = get_avail_buff();
      auto dlen = recvfrom(sock_, &(*buff)[0], buff->size(), 0, (struct sockaddr *)&host, &host_addr_size);
      if (dlen == -1)
      {
#if ANON_LOG_NET_TRAFFIC > 1
        if (errno != EAGAIN)
          anon_log("recvfrom failed with errno: " << errno_string());
#endif
        return;
      }
      else if (dlen == sizeof(buff->size()))
      {
#if ANON_LOG_NET_TRAFFIC > 1
        anon_log("message too big! all " << sizeof(buff->size()) << " bytes consumed in recvfrom call");
#endif
      }
      else
      {
        std::weak_ptr<udp_dispatch> wp = shared_from_this();
        fiber::run_in_fiber([wp, buff, dlen, host, host_addr_size] {
          auto ths = wp.lock();
          if (ths)
          {
            auto clean = clean_sockaddr(host);
            ths->recv_msg(&(*buff)[0], dlen, &clean, host_addr_size);
            ths->release_buff(buff);
          }
        });
      }
    }
  }
  else
    anon_log_error("udp_dispatch::io_avail called with no EPOLLIN. event.events = " << event_bits_to_string(event.events));
}

std::shared_ptr<std::vector<unsigned char>> udp_dispatch::get_avail_buff()
{
  std::unique_lock<std::mutex> l(mtx);
  if (free_buffs.size() > 0)
  {
    auto b = free_buffs.front();
    free_buffs.pop();
    return b;
  }
  return std::make_shared<std::vector<unsigned char>>(65536);
}

void udp_dispatch::release_buff(const std::shared_ptr<std::vector<unsigned char>>& buff)
{
  std::unique_lock<std::mutex> l(mtx);
  free_buffs.push(buff);
}
<|endoftext|>


<commit_before>#include <convolution.hpp>

//#define DEBUG_LEVEL warning
#define DEBUG_LEVEL debug

void init_boost()
{
    logging::core::get()->set_filter
    (
        logging::trivial::severity >= logging::trivial::DEBUG_LEVEL
    );
};

inline void print_header(std::string s){
  using namespace std;
  print_separator(rang::fg::red,s.length()+4);
  cout << rang::fg::red << "║ " << s << " ║" << rang::style::reset << endl;
  print_separator(rang::fg::red,s.length()+4);
}

int main(){
  // Let's initialize Boost logging system
  init_boost();

  BOOST_LOG_TRIVIAL(trace) << "Starting main";

  // Define input parameters
  const size_t input_width = 14;
  const size_t input_height = 14;
  const size_t input_depth = 3;
  const short stride=1;
  const int bias = 0;

  /*
   * GoogLeNet values
   *
  const int num11=128;
  const int num33reduce=128;
  const int num33=256;
  const int num55reduce=24;
  const int num55=64;
  const int poolproj=64;
  */

  const int num1_11=5;
  const int num2_11=5;
  const int num2_33=3;
  const int num3_11=2;
  const int num3_55=6;
  const int num4_11=5;

  /*
   * Let's create the components of the Inception module. For each volume,
   * we first create a convolver object; weights are generated by a stub method.
   * Then, we apply the convolution/pool.
  */
  cl::sycl::queue q;

  print_header("Initializing volumes");
  Volume input_volume=Volume(cl::sycl::range<3>(input_width,input_height,input_depth));
  Volume *vol1, *vol2, *vol3, *vol4, *vol2_t, *vol3_t, *vol4_t;

  initialize_volume(input_volume, true, 255, q);

  print_header("Initializing convolvers");
  Weights weights_1_11 = generate_stub_weights(1,input_depth,num1_11,q);
  convolver c1_11(weights_1_11,stride,bias);
  c1_11.initialize_hard(input_volume,q);

  Weights weights_2_11 = generate_stub_weights(1,input_depth,num2_11,q);
  convolver c2_11(weights_2_11,stride,bias);
  c2_11.initialize_hard(input_volume,q);
  Weights weights_2_33 = generate_stub_weights(3,num2_11,num2_33,q);
  convolver c2_33(weights_2_33,stride,bias);
  c2_33.initialize_soft(&vol2_t,input_width,input_height,num2_11,q);

  Weights weights_3_11 = generate_stub_weights(1,input_depth,num3_11,q);
  convolver c3_11(weights_3_11,stride,bias);
  c3_11.initialize_hard(input_volume,q);
  Weights weights_3_55 = generate_stub_weights(5,num3_11,num3_55,q);
  convolver c3_55(weights_3_55,stride,bias);
  c3_55.initialize_soft(&vol3_t,input_width,input_height,num3_11,q);

  convolver p4_33(3,1);
  p4_33.initialize_hard(input_volume,q);
  Weights weights_4_11 = generate_stub_weights(1,input_depth,num4_11,q);
  convolver c4_11(weights_4_11,stride,bias);
  c4_11.initialize_soft(&vol4_t,input_width,input_height,input_depth,q);

  //std::this_thread::sleep_for(std::chrono::seconds(3));

  print_header("Launching convolutions");
  vol1=c1_11.convolve();

  vol2_t=c2_11.convolve();
  vol2=c2_33.convolve();

  vol3_t=c3_11.convolve();
  vol3=c3_55.convolve();

  vol4_t=p4_33.pool();
  vol4=c4_11.convolve();

  print_volume(*vol1);
  print_volume(*vol2);
  print_volume(*vol3);
  print_volume(*vol4);

  //print_header("Concatenating");
  //Volume output = concatenate_volumes(Weights{*vol1,*vol2,*vol3,*vol4},q);
  //print_header("Final output");
  //print_volume(output);

  std::cout << "Finished." << std::endl;
  return 0;
};
<commit_msg>Working? really?<commit_after>#include <convolution.hpp>

#define DEBUG_LEVEL warning
//#define DEBUG_LEVEL debug

void init_boost()
{
    logging::core::get()->set_filter
    (
        logging::trivial::severity >= logging::trivial::DEBUG_LEVEL
    );
};

inline void print_header(std::string s){
  using namespace std;
  print_separator(rang::fg::red,s.length()+4);
  cout << rang::fg::red << "║ " << s << " ║" << rang::style::reset << endl;
  print_separator(rang::fg::red,s.length()+4);
}

int main(){
  // Let's initialize Boost logging system
  init_boost();

  BOOST_LOG_TRIVIAL(trace) << "Starting main";

  // Define input parameters
  const size_t input_width = 14;
  const size_t input_height = 14;
  const size_t input_depth = 3;
  const short stride=1;
  const int bias = 0;

  /*
   * GoogLeNet values
   *
  const int num11=128;
  const int num33reduce=128;
  const int num33=256;
  const int num55reduce=24;
  const int num55=64;
  const int poolproj=64;
  */

  const int num1_11=5;
  const int num2_11=5;
  const int num2_33=3;
  const int num3_11=2;
  const int num3_55=6;
  const int num4_11=5;

  /*
   * Let's create the components of the Inception module. For each volume,
   * we first create a convolver object; weights are generated by a stub method.
   * Then, we apply the convolution/pool.
  */
  cl::sycl::queue q;

  print_header("Initializing volumes");
  Volume input_volume=Volume(cl::sycl::range<3>(input_width,input_height,input_depth));
  Volume *vol1, *vol2, *vol3, *vol4, *vol2_t, *vol3_t, *vol4_t;

  initialize_volume(input_volume, true, 255, q);

  print_header("Initializing convolvers");
  Weights weights_1_11 = generate_stub_weights(1,input_depth,num1_11,q);
  convolver c1_11(weights_1_11,stride,bias);
  c1_11.initialize_hard(input_volume,q);

  Weights weights_2_11 = generate_stub_weights(1,input_depth,num2_11,q);
  convolver c2_11(weights_2_11,stride,bias);
  c2_11.initialize_hard(input_volume,q);
  Weights weights_2_33 = generate_stub_weights(3,num2_11,num2_33,q);
  convolver c2_33(weights_2_33,stride,bias);
  c2_33.initialize_soft(&vol2_t,input_width,input_height,num2_11,q);

  Weights weights_3_11 = generate_stub_weights(1,input_depth,num3_11,q);
  convolver c3_11(weights_3_11,stride,bias);
  c3_11.initialize_hard(input_volume,q);
  Weights weights_3_55 = generate_stub_weights(5,num3_11,num3_55,q);
  convolver c3_55(weights_3_55,stride,bias);
  c3_55.initialize_soft(&vol3_t,input_width,input_height,num3_11,q);

  convolver p4_33(3,1);
  p4_33.initialize_hard(input_volume,q);
  Weights weights_4_11 = generate_stub_weights(1,input_depth,num4_11,q);
  convolver c4_11(weights_4_11,stride,bias);
  c4_11.initialize_soft(&vol4_t,input_width,input_height,input_depth,q);

  print_header("Launching convolutions");
  vol1=c1_11.convolve();

  vol2_t=c2_11.convolve();
  vol2=c2_33.convolve();

  vol3_t=c3_11.convolve();
  vol3=c3_55.convolve();

  vol4_t=p4_33.pool();
  vol4=c4_11.convolve();

  print_header("Concatenating");
  Volume output = concatenate_volumes(Weights{*vol1,*vol2,*vol3,*vol4},q);
  print_header("Final output");
  print_volume(output);

  std::cout << "Finished." << std::endl;
  return 0;
};
<|endoftext|>