<commit_before>///
/// @file
/// @copyright Copyright (C) 2017, Jonathan Bryan Schmalhofer
///
/// @brief Node to cyclically publish buffered PNG images
///
#include <string>
#include <ros/ros.h>
#include <image_transport/image_transport.h>

sensor_msgs::Image airsim_image_left_msg, airsim_image_right_msg;

int main(int argc, char **argv)
{
    ros::init(argc, argv, "airsim_to_ros_image_publisher_node");
    ros::NodeHandle node_handle;

    ROS_INFO("Starting node");

    image_transport::ImageTransport image_transport(node_handle);
    image_transport::Publisher left_stereoimage_chatter = image_transport.advertise("/airsim/left/image_raw", 1);
    image_transport::Publisher right_stereoimage_chatter = image_transport.advertise("/airsim/right/image_raw", 1);

    std::uint32_t last_sequence_sent = 0;
    while (ros::ok())
    {
        ROS_INFO("Waiting for data");
        int8_t received_return_value = 0;
        if (1 == received_return_value)
        {
            switch (airsim_to_ros.GetImageType())
            {
            case 0: // Unknown
                break;
            case 1: // Left
                ROS_INFO("Left image received");
                // Header
                airsim_image_left_msg.header.seq         = airsim_to_ros.GetImageHeaderSeq();
                airsim_image_left_msg.header.stamp.sec   = airsim_to_ros.GetImageHeaderStampSec();
                airsim_image_left_msg.header.stamp.nsec  = airsim_to_ros.GetImageHeaderStampNsec();
                airsim_image_left_msg.header.frame_id    = airsim_to_ros.GetImageHeaderFrameid();
                // Image
                airsim_image_left_msg.height             = airsim_to_ros.GetImageHeight();
                airsim_image_left_msg.width              = airsim_to_ros.GetImageWidth();
                airsim_image_left_msg.encoding           = airsim_to_ros.GetImageEncoding();
                airsim_image_left_msg.is_bigendian       = airsim_to_ros.GetImageIsBigendian();
                airsim_image_left_msg.step               = airsim_to_ros.GetImageStep();
                airsim_image_left_msg.data.resize(airsim_to_ros.GetImageDataSize());
                memcpy((char*)(&airsim_image_left_msg.data[0]), airsim_to_ros.GetImageData(), airsim_to_ros.GetImageDataSize());
                break;
            case 2: // Right
                ROS_INFO("Right image received");
                // Header
                airsim_image_right_msg.header.seq         = airsim_to_ros.GetImageHeaderSeq();
                airsim_image_right_msg.header.stamp.sec   = airsim_to_ros.GetImageHeaderStampSec();
                airsim_image_right_msg.header.stamp.nsec  = airsim_to_ros.GetImageHeaderStampNsec();
                airsim_image_right_msg.header.frame_id    = airsim_to_ros.GetImageHeaderFrameid();
                // Image
                airsim_image_right_msg.height             = airsim_to_ros.GetImageHeight();
                airsim_image_right_msg.width              = airsim_to_ros.GetImageWidth();
                airsim_image_right_msg.encoding           = airsim_to_ros.GetImageEncoding();
                airsim_image_right_msg.is_bigendian       = airsim_to_ros.GetImageIsBigendian();
                airsim_image_right_msg.step               = airsim_to_ros.GetImageStep();
                airsim_image_right_msg.data.resize(airsim_to_ros.GetImageDataSize());
                memcpy((char*)(&airsim_image_right_msg.data[0]), airsim_to_ros.GetImageData(), airsim_to_ros.GetImageDataSize());
                break;
            default:
                break;
            }

            // TODO: Introduce Debug Mode
            ROS_INFO("Image received");
            ROS_INFO("  Image.header.seq %d", airsim_to_ros.GetImageHeaderSeq());
            ROS_INFO("  Image.header.stamp.sec %d", airsim_to_ros.GetImageHeaderStampSec());
            ROS_INFO("  Image.header.stamp.nsec %d", airsim_to_ros.GetImageHeaderStampNsec());
            ROS_INFO("  Image.header.frame_id %s", airsim_to_ros.GetImageHeaderFrameid());
            ROS_INFO("  Image.height %d", airsim_to_ros.GetImageHeight());
            ROS_INFO("  Image.width %d", airsim_to_ros.GetImageWidth());
            ROS_INFO("  Image.encoding %s", airsim_to_ros.GetImageEncoding());
            ROS_INFO("  Image.is_bigendian %d", airsim_to_ros.GetImageIsBigendian());
            ROS_INFO("  Image.step %d", airsim_to_ros.GetImageStep());
            ROS_INFO("  size(Image.data) %d", airsim_to_ros.GetImageDataSize());

            if (
                    airsim_image_left_msg.header.seq == airsim_image_right_msg.header.seq
                &&  airsim_image_left_msg.header.seq > last_sequence_sent
            )
            {
                ROS_INFO("Images forwarded");
                left_stereoimage_chatter.publish(airsim_image_left_msg);
                right_stereoimage_chatter.publish(airsim_image_right_msg);
            }
        }
        else if (-1 == received_return_value)
        {
            ROS_INFO("Invalid Image received - did not forward");
        }
    }

    return 0;
}
<commit_msg>bugfix for stub<commit_after>///
/// @file
/// @copyright Copyright (C) 2017, Jonathan Bryan Schmalhofer
///
/// @brief Node to cyclically publish buffered PNG images
///
#include <string>
#include <ros/ros.h>
#include <image_transport/image_transport.h>

sensor_msgs::Image airsim_image_left_msg, airsim_image_right_msg;

int main(int argc, char **argv)
{
    ros::init(argc, argv, "airsim_to_ros_image_publisher_node");
    ros::NodeHandle node_handle;

    ROS_INFO("Starting node");

    image_transport::ImageTransport image_transport(node_handle);
    image_transport::Publisher left_stereoimage_chatter = image_transport.advertise("/airsim/left/image_raw", 1);
    image_transport::Publisher right_stereoimage_chatter = image_transport.advertise("/airsim/right/image_raw", 1);

    std::uint32_t last_sequence_sent = 0;
    while (ros::ok())
    {
        ROS_INFO("Waiting for data");
        int8_t received_return_value = 0;
        if (1 == received_return_value)
        {
/*
            switch (airsim_to_ros.GetImageType())
            {
            case 0: // Unknown
                break;
            case 1: // Left
                ROS_INFO("Left image received");
                // Header
                airsim_image_left_msg.header.seq         = airsim_to_ros.GetImageHeaderSeq();
                airsim_image_left_msg.header.stamp.sec   = airsim_to_ros.GetImageHeaderStampSec();
                airsim_image_left_msg.header.stamp.nsec  = airsim_to_ros.GetImageHeaderStampNsec();
                airsim_image_left_msg.header.frame_id    = airsim_to_ros.GetImageHeaderFrameid();
                // Image
                airsim_image_left_msg.height             = airsim_to_ros.GetImageHeight();
                airsim_image_left_msg.width              = airsim_to_ros.GetImageWidth();
                airsim_image_left_msg.encoding           = airsim_to_ros.GetImageEncoding();
                airsim_image_left_msg.is_bigendian       = airsim_to_ros.GetImageIsBigendian();
                airsim_image_left_msg.step               = airsim_to_ros.GetImageStep();
                airsim_image_left_msg.data.resize(airsim_to_ros.GetImageDataSize());
                memcpy((char*)(&airsim_image_left_msg.data[0]), airsim_to_ros.GetImageData(), airsim_to_ros.GetImageDataSize());
                break;
            case 2: // Right
                ROS_INFO("Right image received");
                // Header
                airsim_image_right_msg.header.seq         = airsim_to_ros.GetImageHeaderSeq();
                airsim_image_right_msg.header.stamp.sec   = airsim_to_ros.GetImageHeaderStampSec();
                airsim_image_right_msg.header.stamp.nsec  = airsim_to_ros.GetImageHeaderStampNsec();
                airsim_image_right_msg.header.frame_id    = airsim_to_ros.GetImageHeaderFrameid();
                // Image
                airsim_image_right_msg.height             = airsim_to_ros.GetImageHeight();
                airsim_image_right_msg.width              = airsim_to_ros.GetImageWidth();
                airsim_image_right_msg.encoding           = airsim_to_ros.GetImageEncoding();
                airsim_image_right_msg.is_bigendian       = airsim_to_ros.GetImageIsBigendian();
                airsim_image_right_msg.step               = airsim_to_ros.GetImageStep();
                airsim_image_right_msg.data.resize(airsim_to_ros.GetImageDataSize());
                memcpy((char*)(&airsim_image_right_msg.data[0]), airsim_to_ros.GetImageData(), airsim_to_ros.GetImageDataSize());
                break;
            default:
                break;
            }

            // TODO: Introduce Debug Mode
            ROS_INFO("Image received");
            ROS_INFO("  Image.header.seq %d", airsim_to_ros.GetImageHeaderSeq());
            ROS_INFO("  Image.header.stamp.sec %d", airsim_to_ros.GetImageHeaderStampSec());
            ROS_INFO("  Image.header.stamp.nsec %d", airsim_to_ros.GetImageHeaderStampNsec());
            ROS_INFO("  Image.header.frame_id %s", airsim_to_ros.GetImageHeaderFrameid());
            ROS_INFO("  Image.height %d", airsim_to_ros.GetImageHeight());
            ROS_INFO("  Image.width %d", airsim_to_ros.GetImageWidth());
            ROS_INFO("  Image.encoding %s", airsim_to_ros.GetImageEncoding());
            ROS_INFO("  Image.is_bigendian %d", airsim_to_ros.GetImageIsBigendian());
            ROS_INFO("  Image.step %d", airsim_to_ros.GetImageStep());
            ROS_INFO("  size(Image.data) %d", airsim_to_ros.GetImageDataSize());
*/
            if (
                    airsim_image_left_msg.header.seq == airsim_image_right_msg.header.seq
                &&  airsim_image_left_msg.header.seq > last_sequence_sent
            )
            {
                ROS_INFO("Images forwarded");
                left_stereoimage_chatter.publish(airsim_image_left_msg);
                right_stereoimage_chatter.publish(airsim_image_right_msg);
            }
        }
        else if (-1 == received_return_value)
        {
            ROS_INFO("Invalid Image received - did not forward");
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "Common.h"
#include "CacheAdapters/LevelDB.h"
#include "SSEConfig.h"
#include "SSEEvent.h"

using namespace std;

/**
  Constructor.
  @param config SSEChannelConfig.
**/
LevelDB::LevelDB(const ChannelConfig& config) : _config(config) {
  const string cachefile = _config.server->GetValue("leveldb.storageDir") + "/" + config.id + ".db";
  LOG(INFO) << "LevelDB storage file: " << cachefile;
  InitDB(cachefile);
}

/**
 Destructor.
*/
LevelDB::~LevelDB() {
  leveldb_options_destroy(_options);
  leveldb_writeoptions_destroy(_woptions);
  leveldb_readoptions_destroy(_roptions);
  leveldb_close(_db);
}

/**
 @param dbfile Path where we should create or load the database.
**/
void LevelDB::InitDB(const string& dbfile) {
  char* err = NULL;

  _options = leveldb_options_create();
  _roptions = leveldb_readoptions_create();
  _woptions = leveldb_writeoptions_create();
  leveldb_options_set_create_if_missing(_options, 1);
  _db = leveldb_open(_options, dbfile.c_str(), &err);

  if (err != NULL) {
    LOG(FATAL) << "Failed to open leveldb storage file: " << err;
    leveldb_free(err);
    err = NULL;
  }

  LOG(INFO) << "LevelDB::InitDB finished for " << _config.id;
}

/**
 Add event to cache.
 @patam event Pointer to SSEEvent to cache.
**/
void LevelDB::CacheEvent(SSEEvent* event) {
  char* err = NULL;

  leveldb_put(_db, _woptions, event->getid().c_str(), event->getid().length(),
      event->get().c_str(), event->get().length(), &err);

  if (err != NULL) {
    LOG(ERROR) << "Failed to cache event with id " << event->getid() << ": " << err;
    leveldb_free(err);
    return;
  }

  if (GetSizeOfCachedEvents() > _config.cacheLength) {
    size_t klen;
    char *err = NULL;
    leveldb_iterator_t* it = leveldb_create_iterator(_db, _roptions);

    leveldb_iter_seek_to_first(it);
    const string key = leveldb_iter_key(it, &klen);

    leveldb_delete(_db, _woptions, key.c_str(), klen, &err);

    if (err != NULL) {
      LOG(ERROR) << "Failed to delete key " << key << ": " << err;
      leveldb_free(err);
    } else {
      DLOG(INFO) << "Deleted key " << key;
    }

    leveldb_iter_destroy(it);
  }
}

/**
 Get a list of all events since a givend ID.
 @param lastId ID of first event.
**/
deque<string> LevelDB::GetEventsSinceId(string lastId) {
  deque<string> events;
  leveldb_iterator_t* it;
  leveldb_readoptions_t* readopts;
  const leveldb_snapshot_t* snapshot;

  snapshot = leveldb_create_snapshot(_db);
  readopts = leveldb_readoptions_create();
  leveldb_readoptions_set_snapshot(readopts, snapshot);

  it = leveldb_create_iterator(_db, readopts);

  for (leveldb_iter_seek(it, lastId.c_str(), lastId.length());
      leveldb_iter_valid(it); leveldb_iter_next(it)) {
    size_t vlen;
    const char* val = leveldb_iter_value(it, &vlen);
    events.push_back(val);
  }

  leveldb_iter_destroy(it);
  leveldb_release_snapshot(_db, snapshot);
  leveldb_readoptions_destroy(readopts);
  return events;
}

/**
 Get a list of all events stored in the cache.
**/
deque<string> LevelDB::GetAllEvents() {
  deque<string> events;
  leveldb_iterator_t* it;
  leveldb_readoptions_t* readopts;
  const leveldb_snapshot_t* snapshot;

  snapshot = leveldb_create_snapshot(_db);
  readopts = leveldb_readoptions_create();
  leveldb_readoptions_set_snapshot(readopts, snapshot);

  it = leveldb_create_iterator(_db, readopts);

  for (leveldb_iter_seek_to_first(it); leveldb_iter_valid(it); leveldb_iter_next(it)) {
    size_t vlen;
    const char* val = leveldb_iter_value(it, &vlen);
    events.push_back(val);
  }

  leveldb_iter_destroy(it);
  leveldb_release_snapshot(_db, snapshot);
  leveldb_readoptions_destroy(readopts);

  return events;
}

/**
 Get number of events currently stored in the cache.
**/
int LevelDB::GetSizeOfCachedEvents() {
  leveldb_iterator_t* it;
  leveldb_readoptions_t* readopts;
  const leveldb_snapshot_t* snapshot;
  int n_keys;

  snapshot = leveldb_create_snapshot(_db);
  readopts = leveldb_readoptions_create();
  it = leveldb_create_iterator(_db, readopts);

  leveldb_iter_seek_to_first(it);
  for(n_keys = 0; leveldb_iter_valid(it); leveldb_iter_next(it)) {
    n_keys++;
  }

  leveldb_iter_destroy(it);
  leveldb_release_snapshot(_db, snapshot);
  leveldb_readoptions_destroy(readopts);

  return n_keys;
}
<commit_msg>Make room for the null terminator when storing events in the LevelDB cache.<commit_after>#include "Common.h"
#include "CacheAdapters/LevelDB.h"
#include "SSEConfig.h"
#include "SSEEvent.h"

using namespace std;

/**
  Constructor.
  @param config SSEChannelConfig.
**/
LevelDB::LevelDB(const ChannelConfig& config) : _config(config) {
  const string cachefile = _config.server->GetValue("leveldb.storageDir") + "/" + config.id + ".db";
  LOG(INFO) << "LevelDB storage file: " << cachefile;
  InitDB(cachefile);
}

/**
 Destructor.
*/
LevelDB::~LevelDB() {
  leveldb_options_destroy(_options);
  leveldb_writeoptions_destroy(_woptions);
  leveldb_readoptions_destroy(_roptions);
  leveldb_close(_db);
}

/**
 @param dbfile Path where we should create or load the database.
**/
void LevelDB::InitDB(const string& dbfile) {
  char* err = NULL;

  _options = leveldb_options_create();
  _roptions = leveldb_readoptions_create();
  _woptions = leveldb_writeoptions_create();
  leveldb_options_set_create_if_missing(_options, 1);
  _db = leveldb_open(_options, dbfile.c_str(), &err);

  if (err != NULL) {
    LOG(FATAL) << "Failed to open leveldb storage file: " << err;
    leveldb_free(err);
    err = NULL;
  }

  LOG(INFO) << "LevelDB::InitDB finished for " << _config.id;
}

/**
 Add event to cache.
 @patam event Pointer to SSEEvent to cache.
**/
void LevelDB::CacheEvent(SSEEvent* event) {
  char* err = NULL;

  leveldb_put(_db, _woptions, event->getid().c_str(), event->getid().length()+1,
      event->get().c_str(), event->get().length()+1, &err);

  if (err != NULL) {
    LOG(ERROR) << "Failed to cache event with id " << event->getid() << ": " << err;
    leveldb_free(err);
    return;
  }

  if (GetSizeOfCachedEvents() > _config.cacheLength) {
    size_t klen;
    char *err = NULL;
    leveldb_iterator_t* it = leveldb_create_iterator(_db, _roptions);

    leveldb_iter_seek_to_first(it);
    const string key = leveldb_iter_key(it, &klen);

    leveldb_delete(_db, _woptions, key.c_str(), klen, &err);

    if (err != NULL) {
      LOG(ERROR) << "Failed to delete key " << key << ": " << err;
      leveldb_free(err);
    } else {
      DLOG(INFO) << "Deleted key " << key;
    }

    leveldb_iter_destroy(it);
  }
}

/**
 Get a list of all events since a givend ID.
 @param lastId ID of first event.
**/
deque<string> LevelDB::GetEventsSinceId(string lastId) {
  deque<string> events;
  leveldb_iterator_t* it;
  leveldb_readoptions_t* readopts;
  const leveldb_snapshot_t* snapshot;

  snapshot = leveldb_create_snapshot(_db);
  readopts = leveldb_readoptions_create();
  leveldb_readoptions_set_snapshot(readopts, snapshot);

  it = leveldb_create_iterator(_db, readopts);

  for (leveldb_iter_seek(it, lastId.c_str(), lastId.length());
      leveldb_iter_valid(it); leveldb_iter_next(it)) {
    size_t vlen;
    const char* val = leveldb_iter_value(it, &vlen);
    events.push_back(val);
  }

  leveldb_iter_destroy(it);
  leveldb_release_snapshot(_db, snapshot);
  leveldb_readoptions_destroy(readopts);
  return events;
}

/**
 Get a list of all events stored in the cache.
**/
deque<string> LevelDB::GetAllEvents() {
  deque<string> events;
  leveldb_iterator_t* it;
  leveldb_readoptions_t* readopts;
  const leveldb_snapshot_t* snapshot;

  snapshot = leveldb_create_snapshot(_db);
  readopts = leveldb_readoptions_create();
  leveldb_readoptions_set_snapshot(readopts, snapshot);

  it = leveldb_create_iterator(_db, readopts);

  for (leveldb_iter_seek_to_first(it); leveldb_iter_valid(it); leveldb_iter_next(it)) {
    size_t vlen;
    const char* val = leveldb_iter_value(it, &vlen);
    events.push_back(val);
  }

  leveldb_iter_destroy(it);
  leveldb_release_snapshot(_db, snapshot);
  leveldb_readoptions_destroy(readopts);

  return events;
}

/**
 Get number of events currently stored in the cache.
**/
int LevelDB::GetSizeOfCachedEvents() {
  leveldb_iterator_t* it;
  leveldb_readoptions_t* readopts;
  const leveldb_snapshot_t* snapshot;
  int n_keys;

  snapshot = leveldb_create_snapshot(_db);
  readopts = leveldb_readoptions_create();
  it = leveldb_create_iterator(_db, readopts);

  leveldb_iter_seek_to_first(it);
  for(n_keys = 0; leveldb_iter_valid(it); leveldb_iter_next(it)) {
    n_keys++;
  }

  leveldb_iter_destroy(it);
  leveldb_release_snapshot(_db, snapshot);
  leveldb_readoptions_destroy(readopts);

  return n_keys;
}
<|endoftext|>


<commit_before>#include "slider.h"
#include "qdebug.h"

Slider::Slider(QWidget * parent) : QSlider(parent) {
    setStyleSheet(QString(
                                              "QSlider::groove {"
                                                "border: 1px solid #bbb;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::groove:horizontal {"
                                                "height: 18px;"
                                              "}"

                                              "QSlider::groove:vertical {"
                                                "width: 18px;"
                                              "}"

                                              "QSlider::sub-page:horizontal {"
                                                "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #000, stop: 1 #777);"
                                                "background: qlineargradient(x1: 0, y1: 0.5, x2: 1, y2: 1, stop: 0 #777, stop: 1 #fff);"
                                                "border: 1px solid #777;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::add-page:horizontal {"
                                                "background: #fff;"
                                                "border: 1px solid #777;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::sub-page:vertical {"
                                                  "background: #fff;"
                                                  "border: 1px solid #777;"
                                                  "border-radius: 2px;"
                                              "}"

                                              "QSlider::add-page:vertical {"
                                                  "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #000, stop: 1 #777);"
                                                  "background: qlineargradient(x1: 0, y1: 0.5, x2: 1, y2: 1, stop: 0 #777, stop: 1 #fff);"
                                                  "border: 1px solid #777;"
                                                  "border-radius: 2px;"
                                              "}"

                                              "QSlider::handle {"
                                                "background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc);"
                                                "border: 1px solid #777;"
                                                "margin: 0 -1px;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::handle:horizontal {"
                                                "width: 12px;"
                                              "}"

                                              "QSlider::handle:vertical {"
                                                "height: 12px;"
                                              "}"

                                              "QSlider::handle:hover {"
                                                "background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #fff, stop:1 #ddd);"
                                                "border: 1px solid #444;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::sub-page:disabled {"
                                                "background: #bbb;"
                                                "border-color: #999;"
                                              "}"

                                              "QSlider::add-page:disabled {"
                                                "background: #eee;"
                                                "border-color: #999;"
                                              "}"

                                              "QSlider::handle:disabled {"
                                                "background: #eee;"
                                                "border: 1px solid #aaa;"
                                                "border-radius: 2px;"
                                              "}"
    ));
}

void Slider::paintEvent(QPaintEvent * event) {
    QSlider::paintEvent(event);

    QPainter p(this);

    p.save();

    p.setPen(QColor::fromRgb(0, 0, 0));
    QRect rect = geometry();

    float limit, temp = 0, step = ((float)maximum()) / tickInterval();
    int multiplyer = 0;

    if (orientation() == Qt::Horizontal) {
        while(temp < 20) {
            multiplyer++;
            temp = ((float)rect.width()) / (step / multiplyer);
        }

        step = temp;
        limit = (rect.width() / step) == 0 ? rect.width() - step : rect.width();

        for(float pos = step; pos < limit; pos += step) {
            p.drawLine(pos, rect.top() + 4, pos, rect.bottom() - 7);
        }

        if (multiplyer > 1)
            p.drawText(4, rect.top() + 18, "x " + QString::number(multiplyer));

    } else {
        while(temp < 20) {
            multiplyer++;
            temp = ((float)rect.height()) / (step / multiplyer);
        }

        step = temp;
        limit = (rect.height() / step) == 0 ? rect.height() - step : rect.height();

        for(float pos = step; pos < limit; pos += step) {
            p.drawLine(rect.left() + 4, pos, rect.right() - 7, pos);
        }

        if (multiplyer > 1) {
            p.drawText(rect.left() + 4 + (multiplyer < 10 ? 3 : 0), (int)(limit - step / 2) + 2, "x" + QString::number(multiplyer));
        }
    }

    p.restore();
}
<commit_msg>minor improve<commit_after>#include "slider.h"
#include "qdebug.h"

Slider::Slider(QWidget * parent) : QSlider(parent) {
    setStyleSheet(QString(
                                              "QSlider::groove {"
                                                "border: 1px solid #bbb;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::groove:horizontal {"
                                                "height: 18px;"
                                              "}"

                                              "QSlider::groove:vertical {"
                                                "width: 18px;"
                                              "}"

                                              "QSlider::sub-page:horizontal {"
                                                "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #000, stop: 1 #777);"
                                                "background: qlineargradient(x1: 0, y1: 0.5, x2: 1, y2: 1, stop: 0 #777, stop: 1 #fff);"
                                                "border: 1px solid #777;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::add-page:horizontal {"
                                                "background: #fff;"
                                                "border: 1px solid #777;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::sub-page:vertical {"
                                                  "background: #fff;"
                                                  "border: 1px solid #777;"
                                                  "border-radius: 2px;"
                                              "}"

                                              "QSlider::add-page:vertical {"
                                                  "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #000, stop: 1 #777);"
                                                  "background: qlineargradient(x1: 0, y1: 0.5, x2: 1, y2: 1, stop: 0 #777, stop: 1 #fff);"
                                                  "border: 1px solid #777;"
                                                  "border-radius: 2px;"
                                              "}"

                                              "QSlider::handle {"
                                                "background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc);"
                                                "border: 1px solid #777;"
                                                "margin: 0 -1px;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::handle:horizontal {"
                                                "width: 12px;"
                                              "}"

                                              "QSlider::handle:vertical {"
                                                "height: 12px;"
                                              "}"

                                              "QSlider::handle:hover {"
                                                "background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #fff, stop:1 #ddd);"
                                                "border: 1px solid #444;"
                                                "border-radius: 2px;"
                                              "}"

                                              "QSlider::sub-page:disabled {"
                                                "background: #bbb;"
                                                "border-color: #999;"
                                              "}"

                                              "QSlider::add-page:disabled {"
                                                "background: #eee;"
                                                "border-color: #999;"
                                              "}"

                                              "QSlider::handle:disabled {"
                                                "background: #eee;"
                                                "border: 1px solid #aaa;"
                                                "border-radius: 2px;"
                                              "}"
    ));
}

void Slider::paintEvent(QPaintEvent * event) {
    QSlider::paintEvent(event);

    QPainter p(this);

    p.save();

    p.setPen(QColor::fromRgb(0, 0, 0));
    QRect rect = geometry();

    float limit, temp = 0, step = ((float)maximum()) / tickInterval();
    int multiplyer = 0;

    if (orientation() == Qt::Horizontal) {
        while(temp < 16) {
            multiplyer++;
            temp = ((float)rect.width()) / (step / multiplyer);
        }

        step = temp;
        limit = (rect.width() / step) == 0 ? rect.width() - step : rect.width();

        for(float pos = step; pos < limit; pos += step) {
            p.drawLine(pos, rect.top() + 4, pos, rect.bottom() - 7);
        }

        if (multiplyer > 1)
            p.drawText(4, rect.top() + 18, "x " + QString::number(multiplyer));

    } else {
        while(temp < 20) {
            multiplyer++;
            temp = ((float)rect.height()) / (step / multiplyer);
        }

        step = temp;
        limit = (rect.height() / step) == 0 ? rect.height() - step : rect.height();

        for(float pos = step; pos < limit; pos += step) {
            p.drawLine(rect.left() + 4, pos, rect.right() - 7, pos);
        }

        if (multiplyer > 1) {
            p.drawText(rect.left() + 4 + (multiplyer < 10 ? 3 : 0), (int)(limit - step / 2) + 2, "x" + QString::number(multiplyer));
        }
    }

    p.restore();
}
<|endoftext|>


<commit_before>#include "overlap.h"

using namespace annis;

Overlap::Overlap(DB &db, AnnotationIterator &left, AnnotationIterator &right)
  : left(left), rightAnnotation(right.getAnnotation()), db(db),
    edbLeft(db.getEdgeDB(ComponentType::LEFT_TOKEN, annis_ns, "")),
    edbRight(db.getEdgeDB(ComponentType::RIGHT_TOKEN, annis_ns, "")),
    edbOrder(db.getEdgeDB(ComponentType::ORDERING, annis_ns, "")),
    lhsLeftTokenIt(LeftMostTokenForNodeIterator(left, db)),
    tokenRightFromLHSIt(db, edbOrder, lhsLeftTokenIt, initAnnotation(db.getNodeNameStringID(), 0, db.getNamespaceStringID()), 0, uintmax)
{
  reset();
}

BinaryMatch Overlap::next()
{
  BinaryMatch result;
  result.found = false;

  // TODO: implement overlap
  BinaryMatch rightTokenMatch;

  if(currentMatches.empty())
  {
    rightTokenMatch = tokenRightFromLHSIt.next();
  }
  else
  {
    rightTokenMatch.found = false;
  }
  while(currentMatches.empty() && rightTokenMatch.found)
  {
    result.lhs = lhsLeftTokenIt.currentNodeMatch();

    // get the node that has a right border with the token
    std::vector<nodeid_t> overlapCandidates = edbRight->getOutgoingEdges(rightTokenMatch.rhs.node);
    // also add the token itself
    overlapCandidates.insert(overlapCandidates.begin(), rightTokenMatch.rhs.node);

    // check each candidate if it's left side comes before the right side of the lhs node
    for(unsigned int i=0; i < overlapCandidates.size(); i++)
    {
      nodeid_t candidateID = overlapCandidates[i];
      // the first candidate is always the token itself, otherwise get the aligned token
      nodeid_t leftTokenForCandidate = i == 0 ? candidateID : edbLeft->getOutgoingEdges(candidateID)[0];

      if(edbOrder->isConnected(initEdge(leftTokenForCandidate, rightTokenMatch.rhs.node), 0, uintmax))
      {
        Match m;
        m.node = candidateID;
        for(const Annotation& anno : db.getNodeAnnotationsByID(candidateID))
        {
          if(checkAnnotationEqual(rightAnnotation, anno))
          {
            m.anno = anno;
            currentMatches.push_back(m);
          }
        }
      }
    }

    rightTokenMatch = tokenRightFromLHSIt.next();
  } // end while

  while(!currentMatches.empty())
  {
    result.found = true;
    result.rhs = currentMatches.front();
    currentMatches.pop_front();
  }

  return result;
}

void Overlap::reset()
{
  uniqueMatches.clear();
  left.reset();
  currentMatches.clear();
  lhsLeftTokenIt.reset();
  tokenRightFromLHSIt.reset();
}

Overlap::~Overlap()
{

}

<commit_msg>use left-hand-side<commit_after>#include "overlap.h"

using namespace annis;

Overlap::Overlap(DB &db, AnnotationIterator &left, AnnotationIterator &right)
  : left(left), rightAnnotation(right.getAnnotation()), db(db),
    edbLeft(db.getEdgeDB(ComponentType::LEFT_TOKEN, annis_ns, "")),
    edbRight(db.getEdgeDB(ComponentType::RIGHT_TOKEN, annis_ns, "")),
    edbOrder(db.getEdgeDB(ComponentType::ORDERING, annis_ns, "")),
    lhsLeftTokenIt(left, db),
    tokenRightFromLHSIt(db, edbOrder, lhsLeftTokenIt, initAnnotation(db.getNodeNameStringID(), 0, db.getNamespaceStringID()), 0, uintmax)
{
  reset();
}

BinaryMatch Overlap::next()
{
  BinaryMatch result;
  result.found = false;

  BinaryMatch rightTokenMatch;

  if(currentMatches.empty())
  {
    rightTokenMatch = tokenRightFromLHSIt.next();
  }
  else
  {
    rightTokenMatch.found = false;
  }
  while(currentMatches.empty() && rightTokenMatch.found)
  {
    result.lhs = lhsLeftTokenIt.currentNodeMatch();

    // get the node that has a right border with the token
    std::vector<nodeid_t> overlapCandidates = edbRight->getOutgoingEdges(rightTokenMatch.rhs.node);
    // also add the token itself
    overlapCandidates.insert(overlapCandidates.begin(), rightTokenMatch.rhs.node);

    // check each candidate if it's left side comes before the right side of the lhs node
    for(unsigned int i=0; i < overlapCandidates.size(); i++)
    {
      nodeid_t candidateID = overlapCandidates[i];
      // the first candidate is always the token itself, otherwise get the aligned token
      nodeid_t leftTokenForCandidate = i == 0 ? candidateID : edbLeft->getOutgoingEdges(candidateID)[0];

      if(edbOrder->isConnected(initEdge(leftTokenForCandidate, rightTokenMatch.lhs.node), 0, uintmax))
      {
        Match m;
        m.node = candidateID;
        for(const Annotation& anno : db.getNodeAnnotationsByID(candidateID))
        {
          if(checkAnnotationEqual(rightAnnotation, anno))
          {
            m.anno = anno;
            currentMatches.push_back(m);
          }
        }
      }
    }

    rightTokenMatch = tokenRightFromLHSIt.next();
  } // end while

  while(!currentMatches.empty())
  {
    result.found = true;
    result.rhs = currentMatches.front();
    currentMatches.pop_front();
  }

  return result;
}

void Overlap::reset()
{
  uniqueMatches.clear();
  left.reset();
  currentMatches.clear();
  lhsLeftTokenIt.reset();
  tokenRightFromLHSIt.reset();
}

Overlap::~Overlap()
{

}

<|endoftext|>


<commit_before>// ***************************************************************************
//
//   Generated automatically by genwrapper.
//   Please DO NOT EDIT this file!
//
// ***************************************************************************

#include <osgIntrospection/ReflectionMacros>
#include <osgIntrospection/TypedMethodInfo>
#include <osgIntrospection/StaticMethodInfo>
#include <osgIntrospection/Attributes>

#include <osg/Array>
#include <osgUtil/OperationArrayFunctor>

// Must undefine IN and OUT macros defined in Windows headers
#ifdef IN
#undef IN
#endif
#ifdef OUT
#undef OUT
#endif

BEGIN_VALUE_REFLECTOR(osgUtil::AddRangeOperator)
	I_DeclaringFile("osgUtil/OperationArrayFunctor");
	I_Constructor0(____AddRangeOperator,
	               "",
	               "");
	I_PublicMemberProperty(unsigned int, _begin);
	I_PublicMemberProperty(unsigned int, _count);
	I_PublicMemberProperty(osg::Vec3, _vector);
END_REFLECTOR

BEGIN_VALUE_REFLECTOR(osgUtil::MultiplyRangeOperator)
	I_DeclaringFile("osgUtil/OperationArrayFunctor");
	I_Constructor0(____MultiplyRangeOperator,
	               "",
	               "");
	I_PublicMemberProperty(unsigned int, _begin);
	I_PublicMemberProperty(unsigned int, _count);
	I_PublicMemberProperty(osg::Vec3, _vector);
END_REFLECTOR

TYPE_NAME_ALIAS(osgUtil::OperationArrayFunctor< osgUtil::AddRangeOperator >, osgUtil::AddRangeFunctor)

TYPE_NAME_ALIAS(osgUtil::OperationArrayFunctor< osgUtil::MultiplyRangeOperator >, osgUtil::MultiplyRangeFunctor)

BEGIN_OBJECT_REFLECTOR(osgUtil::OperationArrayFunctor< osgUtil::AddRangeOperator >)
	I_DeclaringFile("osgUtil/OperationArrayFunctor");
	I_BaseType(osg::ArrayVisitor);
	I_Constructor0(____AddRangeOperator >,
	               "",
	               "");
	I_Method1(void, apply, IN, osg::Array &, x,
	          Properties::VIRTUAL,
	          __void__apply__osg_Array_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec2Array &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec2Array_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec3Array &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec3Array_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4Array &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4Array_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4ubArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4ubArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec2bArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec2bArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec3bArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec3bArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4bArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4bArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec2sArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec2sArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec3sArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec3sArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4sArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4sArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec2dArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec2dArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec3dArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec3dArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4dArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4dArray_R1,
	          "",
	          "");
END_REFLECTOR

BEGIN_OBJECT_REFLECTOR(osgUtil::OperationArrayFunctor< osgUtil::MultiplyRangeOperator >)
	I_DeclaringFile("osgUtil/OperationArrayFunctor");
	I_BaseType(osg::ArrayVisitor);
	I_Constructor0(____MultiplyRangeOperator >,
	               "",
	               "");
	I_Method1(void, apply, IN, osg::Array &, x,
	          Properties::VIRTUAL,
	          __void__apply__osg_Array_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec2Array &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec2Array_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec3Array &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec3Array_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4Array &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4Array_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4ubArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4ubArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec2bArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec2bArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec3bArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec3bArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4bArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4bArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec2sArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec2sArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec3sArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec3sArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4sArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4sArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec2dArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec2dArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec3dArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec3dArray_R1,
	          "",
	          "");
	I_Method1(void, apply, IN, osg::Vec4dArray &, array,
	          Properties::VIRTUAL,
	          __void__apply__osg_Vec4dArray_R1,
	          "",
	          "");
END_REFLECTOR

<commit_msg>Removed OperationArrayFunctor for wrappers to avoid compile errors assocaited with them<commit_after><|endoftext|>


<commit_before>/*  This file is part of the KDE project.

    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    Copyright (C) 2008 Matthias Kretz <kretz@kde.org>

    This library is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 2.1 or 3 of the License.

    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, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"
#include "audiooutput.h"
#include "backend.h"
#include "mediaobject.h"
#include "gsthelper.h"
#include <phonon/audiooutput.h>

QT_BEGIN_NAMESPACE

namespace Phonon
{
namespace Gstreamer
{
AudioOutput::AudioOutput(Backend *backend, QObject *parent)
        : QObject(parent)
        , MediaNode(backend, AudioSink)
        , m_volumeLevel(1.0)
        , m_device(0) // ### get from backend
        , m_volumeElement(0)
        , m_audioBin(0)
        , m_audioSink(0)
        , m_conv(0)
{
    static int count = 0;
    m_name = "AudioOutput" + QString::number(count++);
    if (m_backend->isValid()) {
        m_audioBin = gst_bin_new (NULL);
        gst_object_ref (GST_OBJECT (m_audioBin));
        gst_object_sink (GST_OBJECT (m_audioBin));

        m_conv = gst_element_factory_make ("audioconvert", NULL);

        // Get category from parent
        Phonon::Category category = Phonon::NoCategory;
        if (Phonon::AudioOutput *audioOutput = qobject_cast<Phonon::AudioOutput *>(parent))
            category = audioOutput->category();

        m_audioSink = m_backend->deviceManager()->createAudioSink(category);
        m_volumeElement = gst_element_factory_make ("volume", NULL);
        GstElement *queue = gst_element_factory_make ("queue", NULL);
        GstElement *audioresample = gst_element_factory_make ("audioresample", NULL);

        if (queue && m_audioBin && m_conv && audioresample && m_audioSink && m_volumeElement) {
            gst_bin_add_many (GST_BIN (m_audioBin), queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL);

            if (gst_element_link_many (queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL)) {
                // Add ghost sink for audiobin
                GstPad *audiopad = gst_element_get_pad (queue, "sink");
                gst_element_add_pad (m_audioBin, gst_ghost_pad_new ("sink", audiopad));
                gst_object_unref (audiopad);
                m_isValid = true; // Initialization ok, accept input
            }
        }
    }
}

void AudioOutput::mediaNodeEvent(const MediaNodeEvent *event)
{
    if (!m_audioBin)
        return;

    switch (event->type()) {

    default:
        break;
    }
}

AudioOutput::~AudioOutput()
{
    if (m_audioBin) {
        gst_element_set_state (m_audioBin, GST_STATE_NULL);
        gst_object_unref (m_audioBin);
    }
}

qreal AudioOutput::volume() const
{
    return m_volumeLevel;
}

int AudioOutput::outputDevice() const
{
    return m_device;
}

void AudioOutput::setVolume(qreal newVolume)
{
    if (newVolume > 2.0 )
        newVolume = 2.0;
    else if (newVolume < 0.0)
        newVolume = 0.0;

    if (newVolume == m_volumeLevel)
        return;

    m_volumeLevel = newVolume;

    if (m_volumeElement) {
        g_object_set(G_OBJECT(m_volumeElement), "volume", newVolume, (const char*)NULL);
    }

    emit volumeChanged(newVolume);
}

bool AudioOutput::setOutputDevice(int newDevice)
{
    m_backend->logMessage(Q_FUNC_INFO + QString::number(newDevice), Backend::Info, this);
    if (newDevice == m_device)
        return true;

    if (root()) {
        root()->saveState();
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
            return false;
    }

    bool success = false;
    const QList<AudioDevice> deviceList = m_backend->deviceManager()->audioOutputDevices();
    if (m_audioSink &&  newDevice >= 0 && newDevice < deviceList.size()) {
        // Save previous state
        GstState oldState = GST_STATE(m_audioSink);
        const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");
        const QByteArray deviceId = deviceList.at(newDevice).gstId;
        m_device = newDevice;

        // We test if the device can be opened by checking if it can go from NULL to READY state
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
        success = GstHelper::setProperty(m_audioSink, "device", deviceId);
        if (success) {
            success = (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS);
        }
        if (!success) { // Revert state
            m_backend->logMessage(Q_FUNC_INFO +
                                  QLatin1String(" Failed to change device ") +
                                  deviceId, Backend::Info, this);

            GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
            gst_element_set_state(m_audioSink, oldState);
        } else {
            m_backend->logMessage(Q_FUNC_INFO +
                                  QLatin1String(" Successfully changed device ") +
                                  deviceId, Backend::Info, this);
        }

        // Note the stopped state should not really be neccessary, but seems to be required to
        // properly reset after changing the audio state
        if (root()) {
            QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
            root()->resumeState();
        }
    }
    return success;
}

#if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 2, 0))
bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
{
    m_backend->logMessage(Q_FUNC_INFO, Backend::Info, this);
    if (!m_audioSink || !newDevice.isValid()) {
        return false;
    }
    const QVariant driver = newDevice.property("driver");
    if (!driver.isValid()) {
        return setOutputDevice(newDevice.index());
    }
    if (newDevice.index() == m_device) {
        return true;
    }

    if (root()) {
        root()->saveState();
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
            return false;
    }

    // Save previous state
    const GstState oldState = GST_STATE(m_audioSink);
    const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");

    const QByteArray sinkName = GstHelper::property(m_audioSink, "name");
    if (sinkName == "alsasink" || sinkName == "alsasink2") {
        if (driver.toByteArray() != "alsa") {
            return false;
        }
    }

    const QVariant deviceIdsProperty = newDevice.property("deviceIds");
    QStringList deviceIds;
    if (deviceIdsProperty.type() == QVariant::StringList) {
        deviceIds = deviceIdsProperty.toStringList();
    } else if (deviceIdsProperty.type() == QVariant::String) {
        deviceIds += deviceIdsProperty.toString();
    }

    // We test if the device can be opened by checking if it can go from NULL to READY state
    foreach (const QString &deviceId, deviceIds) {
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
        if (GstHelper::setProperty(m_audioSink, "device", deviceId.toUtf8())) {
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
                                  deviceId + QLatin1String(") succeeded"), Backend::Info, this);
            if (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS) {
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
                                      deviceId + QLatin1String(" succeeded"), Backend::Info, this);
                m_device = newDevice.index();
                if (root()) {
                    QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
                    root()->resumeState();
                }
                return true;
            } else {
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
                                      deviceId + QLatin1String(" failed"), Backend::Info, this);
            }
        } else {
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
                                  deviceId + QLatin1String(") failed"), Backend::Info, this);
        }
    }
    // Revert state
    GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
    gst_element_set_state(m_audioSink, oldState);

    if (root()) {
        QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
        root()->resumeState();
    }

    return false;
}
#endif

}
} //namespace Phonon::Gstreamer

QT_END_NAMESPACE
#include "moc_audiooutput.cpp"
<commit_msg>Set the glib appname for gstreamer. This will  allow sound servers such as pulseaudio to show the application name with a volume slider.<commit_after>/*  This file is part of the KDE project.

    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    Copyright (C) 2008 Matthias Kretz <kretz@kde.org>

    This library is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 2.1 or 3 of the License.

    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, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"
#include "audiooutput.h"
#include "backend.h"
#include "mediaobject.h"
#include "gsthelper.h"
#include <phonon/audiooutput.h>

QT_BEGIN_NAMESPACE

namespace Phonon
{
namespace Gstreamer
{
AudioOutput::AudioOutput(Backend *backend, QObject *parent)
        : QObject(parent)
        , MediaNode(backend, AudioSink)
        , m_volumeLevel(1.0)
        , m_device(0) // ### get from backend
        , m_volumeElement(0)
        , m_audioBin(0)
        , m_audioSink(0)
        , m_conv(0)
{
    static int count = 0;
    m_name = "AudioOutput" + QString::number(count++);
    if (m_backend->isValid()) {
        g_set_application_name(qApp->applicationName().toUtf8());
        m_audioBin = gst_bin_new (NULL);
        gst_object_ref (GST_OBJECT (m_audioBin));
        gst_object_sink (GST_OBJECT (m_audioBin));

        m_conv = gst_element_factory_make ("audioconvert", NULL);

        // Get category from parent
        Phonon::Category category = Phonon::NoCategory;
        if (Phonon::AudioOutput *audioOutput = qobject_cast<Phonon::AudioOutput *>(parent))
            category = audioOutput->category();

        m_audioSink = m_backend->deviceManager()->createAudioSink(category);
        m_volumeElement = gst_element_factory_make ("volume", NULL);
        GstElement *queue = gst_element_factory_make ("queue", NULL);
        GstElement *audioresample = gst_element_factory_make ("audioresample", NULL);

        if (queue && m_audioBin && m_conv && audioresample && m_audioSink && m_volumeElement) {
            gst_bin_add_many (GST_BIN (m_audioBin), queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL);

            if (gst_element_link_many (queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL)) {
                // Add ghost sink for audiobin
                GstPad *audiopad = gst_element_get_pad (queue, "sink");
                gst_element_add_pad (m_audioBin, gst_ghost_pad_new ("sink", audiopad));
                gst_object_unref (audiopad);
                m_isValid = true; // Initialization ok, accept input
            }
        }
    }
}

void AudioOutput::mediaNodeEvent(const MediaNodeEvent *event)
{
    if (!m_audioBin)
        return;

    switch (event->type()) {

    default:
        break;
    }
}

AudioOutput::~AudioOutput()
{
    if (m_audioBin) {
        gst_element_set_state (m_audioBin, GST_STATE_NULL);
        gst_object_unref (m_audioBin);
    }
}

qreal AudioOutput::volume() const
{
    return m_volumeLevel;
}

int AudioOutput::outputDevice() const
{
    return m_device;
}

void AudioOutput::setVolume(qreal newVolume)
{
    if (newVolume > 2.0 )
        newVolume = 2.0;
    else if (newVolume < 0.0)
        newVolume = 0.0;

    if (newVolume == m_volumeLevel)
        return;

    m_volumeLevel = newVolume;

    if (m_volumeElement) {
        g_object_set(G_OBJECT(m_volumeElement), "volume", newVolume, (const char*)NULL);
    }

    emit volumeChanged(newVolume);
}

bool AudioOutput::setOutputDevice(int newDevice)
{
    m_backend->logMessage(Q_FUNC_INFO + QString::number(newDevice), Backend::Info, this);
    if (newDevice == m_device)
        return true;

    if (root()) {
        root()->saveState();
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
            return false;
    }

    bool success = false;
    const QList<AudioDevice> deviceList = m_backend->deviceManager()->audioOutputDevices();
    if (m_audioSink &&  newDevice >= 0 && newDevice < deviceList.size()) {
        // Save previous state
        GstState oldState = GST_STATE(m_audioSink);
        const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");
        const QByteArray deviceId = deviceList.at(newDevice).gstId;
        m_device = newDevice;

        // We test if the device can be opened by checking if it can go from NULL to READY state
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
        success = GstHelper::setProperty(m_audioSink, "device", deviceId);
        if (success) {
            success = (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS);
        }
        if (!success) { // Revert state
            m_backend->logMessage(Q_FUNC_INFO +
                                  QLatin1String(" Failed to change device ") +
                                  deviceId, Backend::Info, this);

            GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
            gst_element_set_state(m_audioSink, oldState);
        } else {
            m_backend->logMessage(Q_FUNC_INFO +
                                  QLatin1String(" Successfully changed device ") +
                                  deviceId, Backend::Info, this);
        }

        // Note the stopped state should not really be neccessary, but seems to be required to
        // properly reset after changing the audio state
        if (root()) {
            QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
            root()->resumeState();
        }
    }
    return success;
}

#if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 2, 0))
bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
{
    m_backend->logMessage(Q_FUNC_INFO, Backend::Info, this);
    if (!m_audioSink || !newDevice.isValid()) {
        return false;
    }
    const QVariant driver = newDevice.property("driver");
    if (!driver.isValid()) {
        return setOutputDevice(newDevice.index());
    }
    if (newDevice.index() == m_device) {
        return true;
    }

    if (root()) {
        root()->saveState();
        if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
            return false;
    }

    // Save previous state
    const GstState oldState = GST_STATE(m_audioSink);
    const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");

    const QByteArray sinkName = GstHelper::property(m_audioSink, "name");
    if (sinkName == "alsasink" || sinkName == "alsasink2") {
        if (driver.toByteArray() != "alsa") {
            return false;
        }
    }

    const QVariant deviceIdsProperty = newDevice.property("deviceIds");
    QStringList deviceIds;
    if (deviceIdsProperty.type() == QVariant::StringList) {
        deviceIds = deviceIdsProperty.toStringList();
    } else if (deviceIdsProperty.type() == QVariant::String) {
        deviceIds += deviceIdsProperty.toString();
    }

    // We test if the device can be opened by checking if it can go from NULL to READY state
    foreach (const QString &deviceId, deviceIds) {
        gst_element_set_state(m_audioSink, GST_STATE_NULL);
        if (GstHelper::setProperty(m_audioSink, "device", deviceId.toUtf8())) {
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
                                  deviceId + QLatin1String(") succeeded"), Backend::Info, this);
            if (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS) {
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
                                      deviceId + QLatin1String(" succeeded"), Backend::Info, this);
                m_device = newDevice.index();
                if (root()) {
                    QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
                    root()->resumeState();
                }
                return true;
            } else {
                m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
                                      deviceId + QLatin1String(" failed"), Backend::Info, this);
            }
        } else {
            m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
                                  deviceId + QLatin1String(") failed"), Backend::Info, this);
        }
    }
    // Revert state
    GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
    gst_element_set_state(m_audioSink, oldState);

    if (root()) {
        QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
        root()->resumeState();
    }

    return false;
}
#endif

}
} //namespace Phonon::Gstreamer

QT_END_NAMESPACE
#include "moc_audiooutput.cpp"
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2021 Project CHIP Authors
 *
 *    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.
 */

/**
 *    @file
 *          Provides an implementation of the DiagnosticDataProvider object
 *          for ESP32 platform.
 */

#include <platform/internal/CHIPDeviceLayerInternal.h>

#include <app-common/zap-generated/enums.h>
#include <crypto/CHIPCryptoPAL.h>
#include <platform/DiagnosticDataProvider.h>
#include <platform/ESP32/DiagnosticDataProviderImpl.h>
#include <platform/ESP32/ESP32Utils.h>

#include "esp_event.h"
#include "esp_heap_caps_init.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_spi_flash.h"
#include "esp_system.h"
#include "esp_wifi.h"

using namespace ::chip;
using namespace ::chip::TLV;
using namespace ::chip::DeviceLayer;
using namespace ::chip::DeviceLayer::Internal;
using namespace ::chip::app::Clusters::GeneralDiagnostics;

namespace {

InterfaceType GetInterfaceType(const char * if_desc)
{
    if (strncmp(if_desc, "ap", strnlen(if_desc, 2)) == 0 || strncmp(if_desc, "sta", strnlen(if_desc, 3)) == 0)
        return InterfaceType::EMBER_ZCL_INTERFACE_TYPE_WI_FI;
    if (strncmp(if_desc, "openthread", strnlen(if_desc, 10)) == 0)
        return InterfaceType::EMBER_ZCL_INTERFACE_TYPE_THREAD;
    if (strncmp(if_desc, "eth", strnlen(if_desc, 3)) == 0)
        return InterfaceType::EMBER_ZCL_INTERFACE_TYPE_ETHERNET;
    return InterfaceType::EMBER_ZCL_INTERFACE_TYPE_UNSPECIFIED;
}

#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
uint8_t MapAuthModeToSecurityType(wifi_auth_mode_t authmode)
{
    switch (authmode)
    {
    case WIFI_AUTH_OPEN:
        return 1;
    case WIFI_AUTH_WEP:
        return 2;
    case WIFI_AUTH_WPA_PSK:
        return 3;
    case WIFI_AUTH_WPA2_PSK:
        return 4;
    case WIFI_AUTH_WPA3_PSK:
        return 5;
    default:
        return 0;
    }
}

uint8_t GetWiFiVersionFromAPRecord(wifi_ap_record_t ap_info)
{
    if (ap_info.phy_11n)
        return 3;
    else if (ap_info.phy_11g)
        return 2;
    else if (ap_info.phy_11b)
        return 1;
    else
        return 0;
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI

} // namespace

namespace chip {
namespace DeviceLayer {

DiagnosticDataProviderImpl & DiagnosticDataProviderImpl::GetDefaultInstance()
{
    static DiagnosticDataProviderImpl sInstance;
    return sInstance;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapFree(uint64_t & currentHeapFree)
{
    currentHeapFree = esp_get_free_heap_size();
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapUsed(uint64_t & currentHeapUsed)
{
    currentHeapUsed = heap_caps_get_total_size(MALLOC_CAP_DEFAULT) - esp_get_free_heap_size();
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark)
{
    currentHeapHighWatermark = heap_caps_get_total_size(MALLOC_CAP_DEFAULT) - esp_get_minimum_free_heap_size();
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetRebootCount(uint16_t & rebootCount)
{
    uint32_t count = 0;

    CHIP_ERROR err = ConfigurationMgr().GetRebootCount(count);

    if (err == CHIP_NO_ERROR)
    {
        VerifyOrReturnError(count <= UINT16_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE);
        rebootCount = static_cast<uint16_t>(count);
    }

    return err;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetUpTime(uint64_t & upTime)
{
    System::Clock::Timestamp currentTime = System::SystemClock().GetMonotonicTimestamp();
    System::Clock::Timestamp startTime   = PlatformMgrImpl().GetStartTime();

    if (currentTime >= startTime)
    {
        upTime = std::chrono::duration_cast<System::Clock::Seconds64>(currentTime - startTime).count();
        return CHIP_NO_ERROR;
    }

    return CHIP_ERROR_INVALID_TIME;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours)
{
    uint64_t upTime = 0;

    if (GetUpTime(upTime) == CHIP_NO_ERROR)
    {
        uint32_t totalHours = 0;
        if (ConfigurationMgr().GetTotalOperationalHours(totalHours) == CHIP_NO_ERROR)
        {
            VerifyOrReturnError(upTime / 3600 <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE);
            totalOperationalHours = totalHours + static_cast<uint32_t>(upTime / 3600);
            return CHIP_NO_ERROR;
        }
    }

    return CHIP_ERROR_INVALID_TIME;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetBootReason(BootReasonType & bootReason)
{
    bootReason = BootReasonType::kUnspecified;
    uint8_t reason;
    reason = static_cast<uint8_t>(esp_reset_reason());
    if (reason == ESP_RST_UNKNOWN)
    {
        bootReason = BootReasonType::kUnspecified;
    }
    else if (reason == ESP_RST_POWERON)
    {
        bootReason = BootReasonType::kPowerOnReboot;
    }
    else if (reason == ESP_RST_BROWNOUT)
    {
        bootReason = BootReasonType::kBrownOutReset;
    }
    else if (reason == ESP_RST_SW)
    {
        bootReason = BootReasonType::kSoftwareReset;
    }
    else if (reason == ESP_RST_INT_WDT)
    {
        bootReason = BootReasonType::kSoftwareWatchdogReset;
        /* Reboot can be due to hardware or software watchdog*/
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetNetworkInterfaces(NetworkInterface ** netifpp)
{
    esp_netif_t * netif     = esp_netif_next(NULL);
    NetworkInterface * head = NULL;
    if (netif == NULL)
    {
        ChipLogError(DeviceLayer, "Failed to get network interfaces");
    }
    else
    {
        for (esp_netif_t * ifa = netif; ifa != NULL; ifa = esp_netif_next(ifa))
        {
            NetworkInterface * ifp = new NetworkInterface();
            strncpy(ifp->Name, esp_netif_get_ifkey(ifa), Inet::InterfaceId::kMaxIfNameLength);
            ifp->Name[Inet::InterfaceId::kMaxIfNameLength - 1] = '\0';
            ifp->name                                          = CharSpan::fromCharString(ifp->Name);
            ifp->isOperational                                 = true;
            ifp->type                                          = GetInterfaceType(esp_netif_get_desc(ifa));
            ifp->offPremiseServicesReachableIPv4.SetNull();
            ifp->offPremiseServicesReachableIPv6.SetNull();
            if (esp_netif_get_mac(ifa, ifp->MacAddress) != ESP_OK)
            {
                ChipLogError(DeviceLayer, "Failed to get network hardware address");
            }
            else
            {
                ifp->hardwareAddress = ByteSpan(ifp->MacAddress, 6);
            }
            ifp->Next = head;
            head      = ifp;
        }
    }
    *netifpp = head;
    return CHIP_NO_ERROR;
}

void DiagnosticDataProviderImpl::ReleaseNetworkInterfaces(NetworkInterface * netifp)
{
    while (netifp)
    {
        NetworkInterface * del = netifp;
        netifp                 = netifp->Next;
        delete del;
    }
}

#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiBssId(ByteSpan & BssId)
{
    wifi_ap_record_t ap_info;
    esp_err_t err;
    static uint8_t macAddress[kMaxHardwareAddrSize];

    err = esp_wifi_sta_get_ap_info(&ap_info);
    if (err == ESP_OK)
    {
        memcpy(macAddress, ap_info.bssid, 6);
    }
    BssId = ByteSpan(macAddress, 6);
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiSecurityType(uint8_t & securityType)
{
    securityType = 0;
    wifi_ap_record_t ap_info;
    esp_err_t err;

    err = esp_wifi_sta_get_ap_info(&ap_info);
    if (err == ESP_OK)
    {
        securityType = MapAuthModeToSecurityType(ap_info.authmode);
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiVersion(uint8_t & wifiVersion)
{
    wifiVersion = 0;
    wifi_ap_record_t ap_info;
    esp_err_t err;
    err = esp_wifi_sta_get_ap_info(&ap_info);
    if (err == ESP_OK)
    {
        wifiVersion = GetWiFiVersionFromAPRecord(ap_info);
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiChannelNumber(uint16_t & channelNumber)
{
    channelNumber = 0;
    wifi_ap_record_t ap_info;
    esp_err_t err;

    err = esp_wifi_sta_get_ap_info(&ap_info);
    if (err == ESP_OK)
    {
        channelNumber = ap_info.primary;
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiRssi(int8_t & rssi)
{
    rssi = 0;
    wifi_ap_record_t ap_info;
    esp_err_t err;

    err = esp_wifi_sta_get_ap_info(&ap_info);

    if (err == ESP_OK)
    {
        rssi = ap_info.rssi;
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiBeaconLostCount(uint32_t & beaconLostCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiCurrentMaxRate(uint64_t & currentMaxRate)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiOverrunCount(uint64_t & overrunCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::ResetWiFiNetworkDiagnosticsCounts()
{
    return CHIP_NO_ERROR;
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI

DiagnosticDataProvider & GetDiagnosticDataProviderImpl()
{
    return DiagnosticDataProviderImpl::GetDefaultInstance();
}

} // namespace DeviceLayer
} // namespace chip
<commit_msg>ESP32: Add IPAddresses for the network interfaces in generaldiagnostic cluster (#21271)<commit_after>/*
 *
 *    Copyright (c) 2021 Project CHIP Authors
 *
 *    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.
 */

/**
 *    @file
 *          Provides an implementation of the DiagnosticDataProvider object
 *          for ESP32 platform.
 */

#include <platform/internal/CHIPDeviceLayerInternal.h>

#include <app-common/zap-generated/enums.h>
#include <crypto/CHIPCryptoPAL.h>
#include <platform/DiagnosticDataProvider.h>
#include <platform/ESP32/DiagnosticDataProviderImpl.h>
#include <platform/ESP32/ESP32Utils.h>

#include "esp_event.h"
#include "esp_heap_caps_init.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_spi_flash.h"
#include "esp_system.h"
#include "esp_wifi.h"

using namespace ::chip;
using namespace ::chip::TLV;
using namespace ::chip::DeviceLayer;
using namespace ::chip::DeviceLayer::Internal;
using namespace ::chip::app::Clusters::GeneralDiagnostics;

namespace {

InterfaceType GetInterfaceType(const char * if_desc)
{
    if (strncmp(if_desc, "ap", strnlen(if_desc, 2)) == 0 || strncmp(if_desc, "sta", strnlen(if_desc, 3)) == 0)
        return InterfaceType::EMBER_ZCL_INTERFACE_TYPE_WI_FI;
    if (strncmp(if_desc, "openthread", strnlen(if_desc, 10)) == 0)
        return InterfaceType::EMBER_ZCL_INTERFACE_TYPE_THREAD;
    if (strncmp(if_desc, "eth", strnlen(if_desc, 3)) == 0)
        return InterfaceType::EMBER_ZCL_INTERFACE_TYPE_ETHERNET;
    return InterfaceType::EMBER_ZCL_INTERFACE_TYPE_UNSPECIFIED;
}

#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
uint8_t MapAuthModeToSecurityType(wifi_auth_mode_t authmode)
{
    switch (authmode)
    {
    case WIFI_AUTH_OPEN:
        return 1;
    case WIFI_AUTH_WEP:
        return 2;
    case WIFI_AUTH_WPA_PSK:
        return 3;
    case WIFI_AUTH_WPA2_PSK:
        return 4;
    case WIFI_AUTH_WPA3_PSK:
        return 5;
    default:
        return 0;
    }
}

uint8_t GetWiFiVersionFromAPRecord(wifi_ap_record_t ap_info)
{
    if (ap_info.phy_11n)
        return 3;
    else if (ap_info.phy_11g)
        return 2;
    else if (ap_info.phy_11b)
        return 1;
    else
        return 0;
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI

} // namespace

namespace chip {
namespace DeviceLayer {

DiagnosticDataProviderImpl & DiagnosticDataProviderImpl::GetDefaultInstance()
{
    static DiagnosticDataProviderImpl sInstance;
    return sInstance;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapFree(uint64_t & currentHeapFree)
{
    currentHeapFree = esp_get_free_heap_size();
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapUsed(uint64_t & currentHeapUsed)
{
    currentHeapUsed = heap_caps_get_total_size(MALLOC_CAP_DEFAULT) - esp_get_free_heap_size();
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark)
{
    currentHeapHighWatermark = heap_caps_get_total_size(MALLOC_CAP_DEFAULT) - esp_get_minimum_free_heap_size();
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetRebootCount(uint16_t & rebootCount)
{
    uint32_t count = 0;

    CHIP_ERROR err = ConfigurationMgr().GetRebootCount(count);

    if (err == CHIP_NO_ERROR)
    {
        VerifyOrReturnError(count <= UINT16_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE);
        rebootCount = static_cast<uint16_t>(count);
    }

    return err;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetUpTime(uint64_t & upTime)
{
    System::Clock::Timestamp currentTime = System::SystemClock().GetMonotonicTimestamp();
    System::Clock::Timestamp startTime   = PlatformMgrImpl().GetStartTime();

    if (currentTime >= startTime)
    {
        upTime = std::chrono::duration_cast<System::Clock::Seconds64>(currentTime - startTime).count();
        return CHIP_NO_ERROR;
    }

    return CHIP_ERROR_INVALID_TIME;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours)
{
    uint64_t upTime = 0;

    if (GetUpTime(upTime) == CHIP_NO_ERROR)
    {
        uint32_t totalHours = 0;
        if (ConfigurationMgr().GetTotalOperationalHours(totalHours) == CHIP_NO_ERROR)
        {
            VerifyOrReturnError(upTime / 3600 <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE);
            totalOperationalHours = totalHours + static_cast<uint32_t>(upTime / 3600);
            return CHIP_NO_ERROR;
        }
    }

    return CHIP_ERROR_INVALID_TIME;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetBootReason(BootReasonType & bootReason)
{
    bootReason = BootReasonType::kUnspecified;
    uint8_t reason;
    reason = static_cast<uint8_t>(esp_reset_reason());
    if (reason == ESP_RST_UNKNOWN)
    {
        bootReason = BootReasonType::kUnspecified;
    }
    else if (reason == ESP_RST_POWERON)
    {
        bootReason = BootReasonType::kPowerOnReboot;
    }
    else if (reason == ESP_RST_BROWNOUT)
    {
        bootReason = BootReasonType::kBrownOutReset;
    }
    else if (reason == ESP_RST_SW)
    {
        bootReason = BootReasonType::kSoftwareReset;
    }
    else if (reason == ESP_RST_INT_WDT)
    {
        bootReason = BootReasonType::kSoftwareWatchdogReset;
        /* Reboot can be due to hardware or software watchdog*/
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetNetworkInterfaces(NetworkInterface ** netifpp)
{
    esp_netif_t * netif     = esp_netif_next(NULL);
    NetworkInterface * head = NULL;
    uint8_t ipv6_addr_count = 0;
    esp_ip6_addr_t ip6_addr[kMaxIPv6AddrCount];
    if (netif == NULL)
    {
        ChipLogError(DeviceLayer, "Failed to get network interfaces");
    }
    else
    {
        for (esp_netif_t * ifa = netif; ifa != NULL; ifa = esp_netif_next(ifa))
        {
            NetworkInterface * ifp = new NetworkInterface();
            esp_netif_ip_info_t ipv4_info;
            strncpy(ifp->Name, esp_netif_get_ifkey(ifa), Inet::InterfaceId::kMaxIfNameLength);
            ifp->Name[Inet::InterfaceId::kMaxIfNameLength - 1] = '\0';
            ifp->name                                          = CharSpan::fromCharString(ifp->Name);
            ifp->isOperational                                 = true;
            ifp->type                                          = GetInterfaceType(esp_netif_get_desc(ifa));
            ifp->offPremiseServicesReachableIPv4.SetNull();
            ifp->offPremiseServicesReachableIPv6.SetNull();
            if (esp_netif_get_mac(ifa, ifp->MacAddress) != ESP_OK)
            {
                ChipLogError(DeviceLayer, "Failed to get network hardware address");
            }
            else
            {
                ifp->hardwareAddress = ByteSpan(ifp->MacAddress, 6);
            }
            if (esp_netif_get_ip_info(ifa, &ipv4_info) == ESP_OK)
            {
                memcpy(ifp->Ipv4AddressesBuffer[0], &(ipv4_info.ip.addr), kMaxIPv4AddrSize);
                ifp->Ipv4AddressSpans[0] = ByteSpan(ifp->Ipv4AddressesBuffer[0], kMaxIPv4AddrSize);
                ifp->IPv4Addresses       = chip::app::DataModel::List<chip::ByteSpan>(ifp->Ipv4AddressSpans, 1);
            }
            ipv6_addr_count = esp_netif_get_all_ip6(ifa, ip6_addr);
            for (uint8_t idx = 0; idx < ipv6_addr_count; ++idx)
            {
                memcpy(ifp->Ipv6AddressesBuffer[idx], ip6_addr[idx].addr, kMaxIPv6AddrSize);
                ifp->Ipv6AddressSpans[idx] = ByteSpan(ifp->Ipv6AddressesBuffer[idx], kMaxIPv6AddrSize);
            }
            ifp->IPv6Addresses = chip::app::DataModel::List<chip::ByteSpan>(ifp->Ipv6AddressSpans, ipv6_addr_count);

            ifp->Next = head;
            head      = ifp;
        }
    }
    *netifpp = head;
    return CHIP_NO_ERROR;
}

void DiagnosticDataProviderImpl::ReleaseNetworkInterfaces(NetworkInterface * netifp)
{
    while (netifp)
    {
        NetworkInterface * del = netifp;
        netifp                 = netifp->Next;
        delete del;
    }
}

#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiBssId(ByteSpan & BssId)
{
    wifi_ap_record_t ap_info;
    esp_err_t err;
    static uint8_t macAddress[kMaxHardwareAddrSize];

    err = esp_wifi_sta_get_ap_info(&ap_info);
    if (err == ESP_OK)
    {
        memcpy(macAddress, ap_info.bssid, 6);
    }
    BssId = ByteSpan(macAddress, 6);
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiSecurityType(uint8_t & securityType)
{
    securityType = 0;
    wifi_ap_record_t ap_info;
    esp_err_t err;

    err = esp_wifi_sta_get_ap_info(&ap_info);
    if (err == ESP_OK)
    {
        securityType = MapAuthModeToSecurityType(ap_info.authmode);
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiVersion(uint8_t & wifiVersion)
{
    wifiVersion = 0;
    wifi_ap_record_t ap_info;
    esp_err_t err;
    err = esp_wifi_sta_get_ap_info(&ap_info);
    if (err == ESP_OK)
    {
        wifiVersion = GetWiFiVersionFromAPRecord(ap_info);
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiChannelNumber(uint16_t & channelNumber)
{
    channelNumber = 0;
    wifi_ap_record_t ap_info;
    esp_err_t err;

    err = esp_wifi_sta_get_ap_info(&ap_info);
    if (err == ESP_OK)
    {
        channelNumber = ap_info.primary;
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiRssi(int8_t & rssi)
{
    rssi = 0;
    wifi_ap_record_t ap_info;
    esp_err_t err;

    err = esp_wifi_sta_get_ap_info(&ap_info);

    if (err == ESP_OK)
    {
        rssi = ap_info.rssi;
    }
    return CHIP_NO_ERROR;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiBeaconLostCount(uint32_t & beaconLostCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiCurrentMaxRate(uint64_t & currentMaxRate)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketMulticastRxCount(uint32_t & packetMulticastRxCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketMulticastTxCount(uint32_t & packetMulticastTxCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketUnicastRxCount(uint32_t & packetUnicastRxCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiPacketUnicastTxCount(uint32_t & packetUnicastTxCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetWiFiOverrunCount(uint64_t & overrunCount)
{
    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
}

CHIP_ERROR DiagnosticDataProviderImpl::ResetWiFiNetworkDiagnosticsCounts()
{
    return CHIP_NO_ERROR;
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI

DiagnosticDataProvider & GetDiagnosticDataProviderImpl()
{
    return DiagnosticDataProviderImpl::GetDefaultInstance();
}

} // namespace DeviceLayer
} // namespace chip
<|endoftext|>