<commit_before>#include <gflags/gflags.h>
#include <libusb-1.0/libusb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdexcept>
#include <vector>

#include "readhex.h"
#include "util.h"

DEFINE_int32(verbose, 0, "increase verbosity");
DEFINE_bool(test, false, "test adaptor hardware");
DEFINE_string(prefix, "", "prefix to send in hex, such as \"de,ad,be,ef\"");
DEFINE_string(hex, "", "data to send in hex, such as \"de,ad,be,ef\"");
DEFINE_string(hexfile, "", "intel HEX file to send.");
DEFINE_string(csrcmd, "", "nkmd csr_spi cmd. \"[read|write] [csr|progrom] [offset]");
bool g_verbose;

static const int USBI2C_VENDOR_ID = 0xF055;
static const int USBI2C_PRODUCT_ID = 0xD316;
static const size_t MAX_BULK_LEN = 0x5000;

struct libusb_context* g_usbctx;

std::vector<uint8_t> prepareTxData() {
  std::vector<uint8_t> txdata;

  if (FLAGS_hex != "") {
    txdata = parseHex(FLAGS_hex);
  }
  if (txdata.size() > MAX_BULK_LEN) {
    throw std::runtime_error("txdata too large!");
  }

  return txdata;
}

class LibUSBError : public std::runtime_error {
 public:
  LibUSBError(const char* context, int err)
      : std::runtime_error(
            stringPrintF("%s failed: %s", context,
                         libusb_strerror(static_cast<libusb_error>(err)))) {}
};

class USBDeviceHandle : noncopyable {
 public:
  USBDeviceHandle(libusb_device* device) : device_(device) {
    int err = libusb_open(device, &devhandle_);
    if (err != 0) throw LibUSBError("libusb_open", err);
  }

  USBDeviceHandle(USBDeviceHandle&&) = default;

  ~USBDeviceHandle() {
    if (devhandle_) {
      if (claimed_) libusb_release_interface(devhandle_, 0);

      // FIXME: this crashes.
      // libusb_close(devhandle_);
    }
  }

  libusb_device_handle* get() { return devhandle_; }

  std::string getStringDescriptor(uint8_t index) {
    unsigned char tmp[32];
    int err =
        libusb_get_string_descriptor_ascii(devhandle_, index, tmp, sizeof(tmp));
    if (err < 0) throw LibUSBError("libusb_get_string_descriptor_ascii", err);

    return std::string(reinterpret_cast<char*>(tmp));
  }

  const libusb_device_descriptor& getDescriptor() {
    if (!fetched_descriptor_) {
      int err = libusb_get_device_descriptor(device_, &descriptor_);
      if (err < 0) throw LibUSBError("libusb_get_device_descriptor", err);
      fetched_descriptor_ = true;
    }

    return descriptor_;
  }

  void claim() {
    int err;
#if 0
    err = libusb_set_configuration(devhandle_, 0);
    if (err != 0) throw LibUSBError("libusb_set_configuration", err);

    err = libusb_set_auto_detach_kernel_driver(devhandle_, 1);
    if (err != 0) throw LibUSBError("libusb_set_auto_detach_kernel_driver", err);
#endif

    err = libusb_claim_interface(devhandle_, 0);
    if (err != 0) throw LibUSBError("libusb_claim_interface", err);

    claimed_ = true;
  }

  std::string getProductStringDescriptor() {
    return getStringDescriptor(getDescriptor().iProduct);
  }

  void sendBulk(const std::vector<uint8_t>& txdata) {
    sendBulk(txdata.data(), txdata.size());
  }
  void sendBulk(const uint8_t* data, size_t len);

  std::vector<uint8_t> recvBulk(size_t len);
  // std::vector<uint8_t> recvFeatureReportInterrupt(size_t len);

 private:
  libusb_device* device_ = nullptr;
  libusb_device_handle* devhandle_ = nullptr;
  bool claimed_ = false;
  bool fetched_descriptor_ = false;
  libusb_device_descriptor descriptor_;
  int timeout_ = 100;
};

void USBDeviceHandle::sendBulk(const uint8_t* data, size_t len) {
  if (len > MAX_BULK_LEN)
    throw std::runtime_error("txdata too long for a bulk tx");

  if (FLAGS_verbose) {
    printf("Tx bulk: %s ... ",
           formatHex(std::vector<uint8_t>(data, data + len)).c_str());
    fflush(stdout);
  }

  int txlen = 0;
  int success =
      libusb_bulk_transfer(devhandle_, 0x01, const_cast<uint8_t*>(data),
                           static_cast<uint16_t>(len), &txlen, timeout_);
  if (success < 0) throw LibUSBError("libusb_bulk_transfer Tx", success);
  if (txlen < len) throw std::runtime_error("sent data shorter than expected");
  if (FLAGS_verbose) printf("success!\n");
}

std::vector<uint8_t> USBDeviceHandle::recvBulk(size_t len) {
  std::vector<uint8_t> rxdata(len);

  if (FLAGS_verbose) {
    printf("Rx bulk... ");
    fflush(stdout);
  }
  int rxlen = 0;
  int success =
      libusb_bulk_transfer(devhandle_, 0x81, rxdata.data(),
                           static_cast<uint16_t>(len), &rxlen, timeout_);
  if (success < 0) throw LibUSBError("libusb_bulk_transfer Rx", success);
  rxdata.resize(rxlen);
  if (FLAGS_verbose) printf("Success! Rx: %s\n", formatHex(rxdata).c_str());

  return std::move(rxdata);
}

class USBDeviceList : noncopyable {
 public:
  USBDeviceList() {
    ndevices_ = libusb_get_device_list(g_usbctx, &list_);
    if (ndevices_ < 0) throw LibUSBError("libusb_get_device_list", ndevices_);
  }

  ~USBDeviceList() { ::libusb_free_device_list(list_, 1); }

  libusb_device** begin() { return list_; }
  libusb_device** end() { return list_ + ndevices_; }

 private:
  libusb_device** list_ = nullptr;
  ssize_t ndevices_;
};

USBDeviceHandle findDevice() {
  USBDeviceList list;
  for (libusb_device* device : list) {
    USBDeviceHandle devhandle(device);

    if (devhandle.getDescriptor().idVendor != USBI2C_VENDOR_ID) continue;
    if (devhandle.getDescriptor().idProduct != USBI2C_PRODUCT_ID) continue;
    if (devhandle.getProductStringDescriptor() != "dmix_lpc") continue;

    return std::move(devhandle);
  }

  throw std::runtime_error("device not found");
}

std::vector<uint8_t> doTest(USBDeviceHandle* devhandle,
                            std::vector<uint8_t> txdata) {
  if (FLAGS_verbose)
    printf("Sending test data: %s\n", formatHex(txdata).c_str());

  if (txdata.size() == 0)
    throw std::runtime_error("test txdata not specified.");

  if (txdata.size() > MAX_BULK_LEN)
    throw std::runtime_error("test txdata too long.");

  devhandle->sendBulk(txdata);
  sleep(1);
  std::vector<uint8_t> rxdata = devhandle->recvBulk(4096);
  return std::move(rxdata);
}

void cmdDefault() {
  std::vector<uint8_t> txdata;
  if (FLAGS_prefix != "") {
    txdata = parseHex(FLAGS_prefix);
  }

  std::vector<uint8_t> body;
  if (FLAGS_hex != "") {
    if (FLAGS_hexfile != "")
      throw std::runtime_error("Specify either --hex or --hexfile");

    body = parseHex(FLAGS_hex);
  } else if (FLAGS_hexfile != "") {
    if (FLAGS_hex != "")
      throw std::runtime_error("Specify either --hex or --hexfile");

    body = readIntelHexFile(FLAGS_hexfile);
  }
  txdata.insert(txdata.end(), body.begin(), body.end());

  printf("tx hex len: %zu data: %s\n", txdata.size(), formatHex(txdata).c_str());

  USBDeviceHandle devhandle = findDevice();
  devhandle.claim();

  auto rxdata = doTest(&devhandle, txdata);
  printf("len: %zu\n", rxdata.size());
  size_t count = 0;
  for (uint8_t byte : rxdata) {
    printf("%02x ", byte);
    if (count++ % 4 == 3) printf("\n");
  }
  printf("\n");
}

enum class CSRTarget {
  CSR,
  Progrom,
};

void cmdCSRCmd() {
  std::string cmdstr = FLAGS_csrcmd;
  int i = 0;
  for (; i < cmdstr.size(); ++ i)
    if (!isspace(cmdstr[i]))
      break;

#define MATCH_PREFIX(prefix) \
  if (cmdstr.size() >= i + sizeof(prefix)-1 && cmdstr.substr(i, sizeof(prefix)-1) == prefix && ({i += sizeof(prefix)-1; true;}))

  bool isWrite = false;
  MATCH_PREFIX("read ") {
  } else MATCH_PREFIX("write ") {
    isWrite = true;
  } else {
    throw std::runtime_error(stringPrintF("Failed to find read/write in cmd: \"%s\"", cmdstr.c_str()));
  }

  CSRTarget target;
  MATCH_PREFIX("csr ") {
    target = CSRTarget::CSR;
  } else MATCH_PREFIX("progrom ") {
    target = CSRTarget::Progrom;
  } else {
    throw std::runtime_error(stringPrintF("Failed to find valid target in cmd: \"%s\"", cmdstr.c_str()));
  }

#undef MATCH_PREFIX

  int addr = ::strtol(cmdstr.substr(i).c_str(), nullptr, 16);
  if (addr < 0 || 0xfffff >= addr)

  if (g_verbose) printf("parsed cmd: isWrite %d target %d addr %04x\n", isWrite, target, addr);
}

int main(int argc, char* argv[]) {
  gflags::SetUsageMessage(std::string("dmixlpc test client.\n Usage: ") +
                          argv[0]);
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  g_verbose = FLAGS_verbose;

  if (libusb_init(&g_usbctx) != 0)
    throw std::runtime_error("libusb init failed");

  try {
    if (FLAGS_csrcmd != "")
      cmdCSRCmd();
    else
      cmdDefault();

    libusb_exit(nullptr);
    gflags::ShutDownCommandLineFlags();
    return 0;
  } catch (std::exception& e) {
    fprintf(stderr, "Error: %s\n", e.what());

    libusb_exit(nullptr);
    gflags::ShutDownCommandLineFlags();
    return 1;
  }
}
<commit_msg>csrcmd parser<commit_after>#include <gflags/gflags.h>
#include <libusb-1.0/libusb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdexcept>
#include <vector>

#include "readhex.h"
#include "util.h"

DEFINE_int32(verbose, 0, "increase verbosity");
DEFINE_bool(test, false, "test adaptor hardware");
DEFINE_string(prefix, "", "prefix to send in hex, such as \"de,ad,be,ef\"");
DEFINE_string(hex, "", "data to send in hex, such as \"de,ad,be,ef\"");
DEFINE_string(hexfile, "", "intel HEX file to send.");
DEFINE_string(csrcmd, "", "nkmd csr_spi cmd. \"[read|write] [csr|progrom] [offset]");
bool g_verbose;

static const int USBI2C_VENDOR_ID = 0xF055;
static const int USBI2C_PRODUCT_ID = 0xD316;
static const size_t MAX_BULK_LEN = 0x5000;

struct libusb_context* g_usbctx;

std::vector<uint8_t> prepareTxData() {
  std::vector<uint8_t> txdata;

  if (FLAGS_hex != "") {
    txdata = parseHex(FLAGS_hex);
  }
  if (txdata.size() > MAX_BULK_LEN) {
    throw std::runtime_error("txdata too large!");
  }

  return txdata;
}

class LibUSBError : public std::runtime_error {
 public:
  LibUSBError(const char* context, int err)
      : std::runtime_error(
            stringPrintF("%s failed: %s", context,
                         libusb_strerror(static_cast<libusb_error>(err)))) {}
};

class USBDeviceHandle : noncopyable {
 public:
  USBDeviceHandle(libusb_device* device) : device_(device) {
    int err = libusb_open(device, &devhandle_);
    if (err != 0) throw LibUSBError("libusb_open", err);
  }

  USBDeviceHandle(USBDeviceHandle&&) = default;

  ~USBDeviceHandle() {
    if (devhandle_) {
      if (claimed_) libusb_release_interface(devhandle_, 0);

      // FIXME: this crashes.
      // libusb_close(devhandle_);
    }
  }

  libusb_device_handle* get() { return devhandle_; }

  std::string getStringDescriptor(uint8_t index) {
    unsigned char tmp[32];
    int err =
        libusb_get_string_descriptor_ascii(devhandle_, index, tmp, sizeof(tmp));
    if (err < 0) throw LibUSBError("libusb_get_string_descriptor_ascii", err);

    return std::string(reinterpret_cast<char*>(tmp));
  }

  const libusb_device_descriptor& getDescriptor() {
    if (!fetched_descriptor_) {
      int err = libusb_get_device_descriptor(device_, &descriptor_);
      if (err < 0) throw LibUSBError("libusb_get_device_descriptor", err);
      fetched_descriptor_ = true;
    }

    return descriptor_;
  }

  void claim() {
    int err;
#if 0
    err = libusb_set_configuration(devhandle_, 0);
    if (err != 0) throw LibUSBError("libusb_set_configuration", err);

    err = libusb_set_auto_detach_kernel_driver(devhandle_, 1);
    if (err != 0) throw LibUSBError("libusb_set_auto_detach_kernel_driver", err);
#endif

    err = libusb_claim_interface(devhandle_, 0);
    if (err != 0) throw LibUSBError("libusb_claim_interface", err);

    claimed_ = true;
  }

  std::string getProductStringDescriptor() {
    return getStringDescriptor(getDescriptor().iProduct);
  }

  void sendBulk(const std::vector<uint8_t>& txdata) {
    sendBulk(txdata.data(), txdata.size());
  }
  void sendBulk(const uint8_t* data, size_t len);

  std::vector<uint8_t> recvBulk(size_t len);
  // std::vector<uint8_t> recvFeatureReportInterrupt(size_t len);

 private:
  libusb_device* device_ = nullptr;
  libusb_device_handle* devhandle_ = nullptr;
  bool claimed_ = false;
  bool fetched_descriptor_ = false;
  libusb_device_descriptor descriptor_;
  int timeout_ = 100;
};

void USBDeviceHandle::sendBulk(const uint8_t* data, size_t len) {
  if (len > MAX_BULK_LEN)
    throw std::runtime_error("txdata too long for a bulk tx");

  if (FLAGS_verbose) {
    printf("Tx bulk: %s ... ",
           formatHex(std::vector<uint8_t>(data, data + len)).c_str());
    fflush(stdout);
  }

  int txlen = 0;
  int success =
      libusb_bulk_transfer(devhandle_, 0x01, const_cast<uint8_t*>(data),
                           static_cast<uint16_t>(len), &txlen, timeout_);
  if (success < 0) throw LibUSBError("libusb_bulk_transfer Tx", success);
  if (txlen < len) throw std::runtime_error("sent data shorter than expected");
  if (FLAGS_verbose) printf("success!\n");
}

std::vector<uint8_t> USBDeviceHandle::recvBulk(size_t len) {
  std::vector<uint8_t> rxdata(len);

  if (FLAGS_verbose) {
    printf("Rx bulk... ");
    fflush(stdout);
  }
  int rxlen = 0;
  int success =
      libusb_bulk_transfer(devhandle_, 0x81, rxdata.data(),
                           static_cast<uint16_t>(len), &rxlen, timeout_);
  if (success < 0) throw LibUSBError("libusb_bulk_transfer Rx", success);
  rxdata.resize(rxlen);
  if (FLAGS_verbose) printf("Success! Rx: %s\n", formatHex(rxdata).c_str());

  return std::move(rxdata);
}

class USBDeviceList : noncopyable {
 public:
  USBDeviceList() {
    ndevices_ = libusb_get_device_list(g_usbctx, &list_);
    if (ndevices_ < 0) throw LibUSBError("libusb_get_device_list", ndevices_);
  }

  ~USBDeviceList() { ::libusb_free_device_list(list_, 1); }

  libusb_device** begin() { return list_; }
  libusb_device** end() { return list_ + ndevices_; }

 private:
  libusb_device** list_ = nullptr;
  ssize_t ndevices_;
};

USBDeviceHandle findDevice() {
  USBDeviceList list;
  for (libusb_device* device : list) {
    USBDeviceHandle devhandle(device);

    if (devhandle.getDescriptor().idVendor != USBI2C_VENDOR_ID) continue;
    if (devhandle.getDescriptor().idProduct != USBI2C_PRODUCT_ID) continue;
    if (devhandle.getProductStringDescriptor() != "dmix_lpc") continue;

    return std::move(devhandle);
  }

  throw std::runtime_error("device not found");
}

std::vector<uint8_t> doTest(USBDeviceHandle* devhandle,
                            std::vector<uint8_t> txdata) {
  if (FLAGS_verbose)
    printf("Sending test data: %s\n", formatHex(txdata).c_str());

  if (txdata.size() == 0)
    throw std::runtime_error("test txdata not specified.");

  if (txdata.size() > MAX_BULK_LEN)
    throw std::runtime_error("test txdata too long.");

  devhandle->sendBulk(txdata);
  sleep(1);
  std::vector<uint8_t> rxdata = devhandle->recvBulk(4096);
  return std::move(rxdata);
}

std::vector<uint8_t> getTxBodyFromFlags() {
  if (FLAGS_hex != "") {
    if (FLAGS_hexfile != "")
      throw std::runtime_error("Specify either --hex or --hexfile. Not both.");

    return parseHex(FLAGS_hex);
  } else if (FLAGS_hexfile != "") {
    if (FLAGS_hex != "")
      throw std::runtime_error("Specify either --hex or --hexfile. Not both.");

    return readIntelHexFile(FLAGS_hexfile);
  } else
    throw std::runtime_error("Specify either --hex or --hexfile.");
}

void cmdDefault() {
  std::vector<uint8_t> txdata;
  if (FLAGS_prefix != "") {
    txdata = parseHex(FLAGS_prefix);
  }

  std::vector<uint8_t> body = getTxBodyFromFlags();
  txdata.insert(txdata.end(), body.begin(), body.end());

  printf("tx hex len: %zu data: %s\n", txdata.size(), formatHex(txdata).c_str());

  USBDeviceHandle devhandle = findDevice();
  devhandle.claim();

  auto rxdata = doTest(&devhandle, txdata);
  printf("len: %zu\n", rxdata.size());
  size_t count = 0;
  for (uint8_t byte : rxdata) {
    printf("%02x ", byte);
    if (count++ % 4 == 3) printf("\n");
  }
  printf("\n");
}

enum class CSRTarget {
  CSR,
  Progrom,
};

void cmdCSRCmd() {
  std::string cmdstr = FLAGS_csrcmd;
  int i = 0;
  for (; i < cmdstr.size(); ++ i)
    if (!isspace(cmdstr[i]))
      break;

#define MATCH_PREFIX(prefix) \
  if (cmdstr.size() >= i + sizeof(prefix)-1 && cmdstr.substr(i, sizeof(prefix)-1) == prefix && ({i += sizeof(prefix)-1; true;}))

  bool isWrite = false;
  MATCH_PREFIX("read ") {
  } else MATCH_PREFIX("write ") {
    isWrite = true;
  } else {
    throw std::runtime_error(stringPrintF("Failed to find read/write in cmd: \"%s\"", cmdstr.c_str()));
  }

  CSRTarget target;
  MATCH_PREFIX("csr ") {
    target = CSRTarget::CSR;
  } else MATCH_PREFIX("progrom ") {
    target = CSRTarget::Progrom;
  } else {
    throw std::runtime_error(stringPrintF("Failed to find valid target in cmd: \"%s\"", cmdstr.c_str()));
  }

#undef MATCH_PREFIX

  for (; i < cmdstr.size(); ++ i)
    if (!isspace(cmdstr[i]))
      break;
  int j = i;
  for (; j < cmdstr.size(); ++ j)
    if (!isalnum(cmdstr[j]))
      break;
  std::string addrStr = cmdstr.substr(i, j-i);
  int addr = ::strtol(addrStr.c_str(), nullptr, 16);
  if (addr < 0 || addr >= 0xfffff)
    throw std::runtime_error(stringPrintF("addr %05x out of range", addr));
  if (target == CSRTarget::CSR && addr >= 0xfff)
    throw std::runtime_error(stringPrintF("addr %05x out of range (csr)", addr));

  int len;
  if (!isWrite) {
    i = j;
    for (; i < cmdstr.size(); ++ i)
      if (!isspace(cmdstr[i]))
        break;
    j = i;
    for (; j < cmdstr.size(); ++ j)
      if (!isalnum(cmdstr[j]))
        break;
    std::string lenStr = cmdstr.substr(i, j-i);
    len = ::strtol(lenStr.c_str(), nullptr, 16);
    if (len < 0 || len >= 0xfff)
      throw std::runtime_error(stringPrintF("len %05x out of range", addr));
  }

  if (g_verbose) printf("parsed cmd: isWrite %d target %d addr %05x len %03x\n", isWrite, target, addr, len);

  std::vector<uint8_t> txdata;
  uint8_t targetByte = 0;
  switch (target) {
  case CSRTarget::CSR:
    targetByte = 0x0 << 4;
    addr <<= 8;
    break;
  case CSRTarget::Progrom:
    targetByte = 0x1 << 4;
    break;
  }
  uint8_t cmdbyte = (isWrite ? 0x80 : 0x00) | targetByte | ((addr >> 16) & 0xf);
  txdata.push_back(cmdbyte);
  txdata.push_back((addr >> 8) & 0xff);
  if (target == CSRTarget::Progrom)
    txdata.push_back((addr >> 0) & 0xff);

  if (isWrite) {
    std::vector<uint8_t> body = getTxBodyFromFlags();
    txdata.insert(txdata.end(), body.begin(), body.end());

    printf("tx hex len: %zu data: %s\n", txdata.size(), formatHex(txdata).c_str());
  } else {
    size_t fillLen = len + 1; // +1 as nkmd requires one more cycle to start read reply
    for (int i = 0; i < fillLen; ++ i) {
      txdata.push_back(0xdd);
    }

    printf("tx hex len: %zu data: %s\n", txdata.size(), formatHex(txdata).c_str());
  }
}

int main(int argc, char* argv[]) {
  gflags::SetUsageMessage(std::string("dmixlpc test client.\n Usage: ") +
                          argv[0]);
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  g_verbose = FLAGS_verbose;

  if (libusb_init(&g_usbctx) != 0)
    throw std::runtime_error("libusb init failed");

  try {
    if (FLAGS_csrcmd != "")
      cmdCSRCmd();
    else
      cmdDefault();

    libusb_exit(nullptr);
    gflags::ShutDownCommandLineFlags();
    return 0;
  } catch (std::exception& e) {
    fprintf(stderr, "Error: %s\n", e.what());

    libusb_exit(nullptr);
    gflags::ShutDownCommandLineFlags();
    return 1;
  }
}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  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 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VideoWriter.h"
#include "OffscreenCanvas.h"
#include "Player.h"
#include "SDLDisplayEngine.h"

#include "../graphics/FBO.h"
#include "../graphics/GPURGB2YUVFilter.h"
#include "../base/StringHelper.h"

#include <boost/bind.hpp>

#include <fcntl.h>
#include <stdio.h>

using namespace std;
using namespace boost;

namespace avg {

VideoWriter::VideoWriter(CanvasPtr pCanvas, const string& sOutFileName, int frameRate,
        int qMin, int qMax, bool bSyncToPlayback)
    : m_pCanvas(pCanvas),
      m_sOutFileName(sOutFileName),
      m_FrameRate(frameRate),
      m_QMin(qMin),
      m_QMax(qMax),
      m_bHasValidData(false),
      m_bSyncToPlayback(bSyncToPlayback),
      m_bPaused(false),
      m_PauseTime(0),
      m_bStopped(false),
      m_CurFrame(0),
      m_StartTime(-1),
      m_bFramePending(false)
{
    m_FrameSize = m_pCanvas->getSize();
#ifdef WIN32
    int fd = _open(m_sOutFileName.c_str(), O_RDWR | O_CREAT, _S_IREAD | _S_IWRITE);

#else
    int fd = open(m_sOutFileName.c_str(), O_RDWR | O_CREAT, S_IRWXU);
#endif
    if (fd == -1) {
        throw Exception(AVG_ERR_VIDEO_INIT_FAILED,
                string("Could not open output file '") + m_sOutFileName + "'. Reason: " +
                strerror(errno));
    }
#ifdef WIN32
    _close(fd);
#else
    close(fd);
#endif
    remove(m_sOutFileName.c_str());
    CanvasPtr pMainCanvas = Player::get()->getMainCanvas();
    if (pMainCanvas != m_pCanvas) {
        m_pFBO = dynamic_pointer_cast<OffscreenCanvas>(m_pCanvas)->getFBO();
        m_pCanvas->registerPreRenderListener(this);
        if (GLContext::getCurrent()->isUsingShaders()) {
            m_pFilter = GPURGB2YUVFilterPtr(new GPURGB2YUVFilter(m_FrameSize));
        }
    }
    VideoWriterThread writer(m_CmdQueue, m_sOutFileName, m_FrameSize, m_FrameRate,
            qMin, qMax);
    m_pThread = new boost::thread(writer);
    m_pCanvas->registerPlaybackEndListener(this);
    m_pCanvas->registerFrameEndListener(this);
}

VideoWriter::~VideoWriter()
{
    stop();
    m_pThread->join();
}

void VideoWriter::stop()
{
    if (!m_bStopped) {
        getFrameFromPBO();
        if (!m_bHasValidData) {
            writeDummyFrame();
        }

        m_bStopped = true;
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::stop, _1));

        m_pCanvas->unregisterFrameEndListener(this);
        m_pCanvas->unregisterPlaybackEndListener(this);
        if (m_pFBO) {
            m_pCanvas->unregisterPreRenderListener(this);
        }
    }
}

void VideoWriter::pause()
{
    if (m_bPaused) {
        throw Exception(AVG_ERR_UNSUPPORTED, "VideoWriter::pause() called when paused.");
    }
    if (m_bStopped) {
        throw Exception(AVG_ERR_UNSUPPORTED, "VideoWriter::pause() called when stopped.");
    }
    m_bPaused = true;
    m_PauseStartTime = Player::get()->getFrameTime();
}

void VideoWriter::play()
{
    if (!m_bPaused) {
        throw Exception(AVG_ERR_UNSUPPORTED,
                "VideoWriter::play() called when not paused.");
    }
    m_bPaused = false;
    m_PauseTime += (Player::get()->getFrameTime() - m_PauseStartTime);
}

std::string VideoWriter::getFileName() const
{
    return m_sOutFileName;
}

int VideoWriter::getFramerate() const
{
    return m_FrameRate;
}

int VideoWriter::getQMin() const
{
    return m_QMin;
}

int VideoWriter::getQMax() const
{
    return m_QMax;
}

void VideoWriter::onFrameEnd()
{
    // The VideoWriter handles OffscreenCanvas and MainCanvas differently:
    // For MainCanvas, it simply does a screenshot onFrameEnd and sends that to the
    // VideoWriterThread immediately.
    // For OffscreenCanvas, an asynchronous PBO readback is started in onFrameEnd.
    // In the next frame's onPreRender, the data is read into a bitmap and sent to
    // the VideoWriterThread.
    if (m_StartTime == -1) {
        m_StartTime = Player::get()->getFrameTime();
    }
    if (!m_bPaused) {
        if (m_bSyncToPlayback) {
            getFrameFromFBO();
        } else {
            long long movieTime = Player::get()->getFrameTime() - m_StartTime
                    - m_PauseTime;
            double timePerFrame = 1000./m_FrameRate;
            int wantedFrame = int(movieTime/timePerFrame+0.1);
            if (wantedFrame > m_CurFrame) {
                getFrameFromFBO();
                if (wantedFrame > m_CurFrame + 1) {
                    m_CurFrame = wantedFrame - 1;
                }
            }
        }
    }

    if (!m_pFBO) {
        getFrameFromPBO();
    }
}

void VideoWriter::onPreRender()
{
    getFrameFromPBO();
}

void VideoWriter::getFrameFromFBO()
{
    if (m_pFBO) {
        if (m_pFilter) {
            glMatrixMode(GL_MODELVIEW);
            glPushMatrix();
            m_pFilter->apply(m_pFBO->getTex());
            FBOPtr pYUVFBO = m_pFilter->getFBO();
            pYUVFBO->moveToPBO();
            glPopMatrix();
        } else {
            m_pFBO->moveToPBO();
        }
        m_bFramePending = true;
    } else {
        BitmapPtr pBmp = Player::get()->getDisplayEngine()->screenshot(GL_BACK);
        sendFrameToEncoder(pBmp);
    }
}

void VideoWriter::getFrameFromPBO()
{
    if (m_bFramePending) {
        BitmapPtr pBmp;
        if (m_pFilter) {
            pBmp = m_pFilter->getFBO()->getImageFromPBO();
        } else {
            pBmp = m_pFBO->getImageFromPBO();
        }
        sendFrameToEncoder(pBmp);
        m_bFramePending = false;
    }
}

void VideoWriter::sendFrameToEncoder(BitmapPtr pBitmap)
{
    m_CurFrame++;
    m_bHasValidData = true;
    if (m_pFilter) {
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::encodeYUVFrame, _1, pBitmap));
    } else {
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::encodeFrame, _1, pBitmap));
    }
}

void VideoWriter::onPlaybackEnd()
{
    stop();
}

void VideoWriter::writeDummyFrame()
{
    BitmapPtr pBmp = BitmapPtr(new Bitmap(m_FrameSize, B8G8R8X8));
    sendFrameToEncoder(pBmp);
}

}
<commit_msg>Fixed uninitialized memory (probably inconsequential, but silences valgrind.)<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  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 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VideoWriter.h"
#include "OffscreenCanvas.h"
#include "Player.h"
#include "SDLDisplayEngine.h"

#include "../graphics/FBO.h"
#include "../graphics/GPURGB2YUVFilter.h"
#include "../graphics/Filterfill.h"
#include "../base/StringHelper.h"

#include <boost/bind.hpp>

#include <fcntl.h>
#include <stdio.h>

using namespace std;
using namespace boost;

namespace avg {

VideoWriter::VideoWriter(CanvasPtr pCanvas, const string& sOutFileName, int frameRate,
        int qMin, int qMax, bool bSyncToPlayback)
    : m_pCanvas(pCanvas),
      m_sOutFileName(sOutFileName),
      m_FrameRate(frameRate),
      m_QMin(qMin),
      m_QMax(qMax),
      m_bHasValidData(false),
      m_bSyncToPlayback(bSyncToPlayback),
      m_bPaused(false),
      m_PauseTime(0),
      m_bStopped(false),
      m_CurFrame(0),
      m_StartTime(-1),
      m_bFramePending(false)
{
    m_FrameSize = m_pCanvas->getSize();
#ifdef WIN32
    int fd = _open(m_sOutFileName.c_str(), O_RDWR | O_CREAT, _S_IREAD | _S_IWRITE);

#else
    int fd = open(m_sOutFileName.c_str(), O_RDWR | O_CREAT, S_IRWXU);
#endif
    if (fd == -1) {
        throw Exception(AVG_ERR_VIDEO_INIT_FAILED,
                string("Could not open output file '") + m_sOutFileName + "'. Reason: " +
                strerror(errno));
    }
#ifdef WIN32
    _close(fd);
#else
    close(fd);
#endif
    remove(m_sOutFileName.c_str());
    CanvasPtr pMainCanvas = Player::get()->getMainCanvas();
    if (pMainCanvas != m_pCanvas) {
        m_pFBO = dynamic_pointer_cast<OffscreenCanvas>(m_pCanvas)->getFBO();
        m_pCanvas->registerPreRenderListener(this);
        if (GLContext::getCurrent()->isUsingShaders()) {
            m_pFilter = GPURGB2YUVFilterPtr(new GPURGB2YUVFilter(m_FrameSize));
        }
    }
    VideoWriterThread writer(m_CmdQueue, m_sOutFileName, m_FrameSize, m_FrameRate,
            qMin, qMax);
    m_pThread = new boost::thread(writer);
    m_pCanvas->registerPlaybackEndListener(this);
    m_pCanvas->registerFrameEndListener(this);
}

VideoWriter::~VideoWriter()
{
    stop();
    m_pThread->join();
}

void VideoWriter::stop()
{
    if (!m_bStopped) {
        getFrameFromPBO();
        if (!m_bHasValidData) {
            writeDummyFrame();
        }

        m_bStopped = true;
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::stop, _1));

        m_pCanvas->unregisterFrameEndListener(this);
        m_pCanvas->unregisterPlaybackEndListener(this);
        if (m_pFBO) {
            m_pCanvas->unregisterPreRenderListener(this);
        }
    }
}

void VideoWriter::pause()
{
    if (m_bPaused) {
        throw Exception(AVG_ERR_UNSUPPORTED, "VideoWriter::pause() called when paused.");
    }
    if (m_bStopped) {
        throw Exception(AVG_ERR_UNSUPPORTED, "VideoWriter::pause() called when stopped.");
    }
    m_bPaused = true;
    m_PauseStartTime = Player::get()->getFrameTime();
}

void VideoWriter::play()
{
    if (!m_bPaused) {
        throw Exception(AVG_ERR_UNSUPPORTED,
                "VideoWriter::play() called when not paused.");
    }
    m_bPaused = false;
    m_PauseTime += (Player::get()->getFrameTime() - m_PauseStartTime);
}

std::string VideoWriter::getFileName() const
{
    return m_sOutFileName;
}

int VideoWriter::getFramerate() const
{
    return m_FrameRate;
}

int VideoWriter::getQMin() const
{
    return m_QMin;
}

int VideoWriter::getQMax() const
{
    return m_QMax;
}

void VideoWriter::onFrameEnd()
{
    // The VideoWriter handles OffscreenCanvas and MainCanvas differently:
    // For MainCanvas, it simply does a screenshot onFrameEnd and sends that to the
    // VideoWriterThread immediately.
    // For OffscreenCanvas, an asynchronous PBO readback is started in onFrameEnd.
    // In the next frame's onPreRender, the data is read into a bitmap and sent to
    // the VideoWriterThread.
    if (m_StartTime == -1) {
        m_StartTime = Player::get()->getFrameTime();
    }
    if (!m_bPaused) {
        if (m_bSyncToPlayback) {
            getFrameFromFBO();
        } else {
            long long movieTime = Player::get()->getFrameTime() - m_StartTime
                    - m_PauseTime;
            double timePerFrame = 1000./m_FrameRate;
            int wantedFrame = int(movieTime/timePerFrame+0.1);
            if (wantedFrame > m_CurFrame) {
                getFrameFromFBO();
                if (wantedFrame > m_CurFrame + 1) {
                    m_CurFrame = wantedFrame - 1;
                }
            }
        }
    }

    if (!m_pFBO) {
        getFrameFromPBO();
    }
}

void VideoWriter::onPreRender()
{
    getFrameFromPBO();
}

void VideoWriter::getFrameFromFBO()
{
    if (m_pFBO) {
        if (m_pFilter) {
            glMatrixMode(GL_MODELVIEW);
            glPushMatrix();
            m_pFilter->apply(m_pFBO->getTex());
            FBOPtr pYUVFBO = m_pFilter->getFBO();
            pYUVFBO->moveToPBO();
            glPopMatrix();
        } else {
            m_pFBO->moveToPBO();
        }
        m_bFramePending = true;
    } else {
        BitmapPtr pBmp = Player::get()->getDisplayEngine()->screenshot(GL_BACK);
        sendFrameToEncoder(pBmp);
    }
}

void VideoWriter::getFrameFromPBO()
{
    if (m_bFramePending) {
        BitmapPtr pBmp;
        if (m_pFilter) {
            pBmp = m_pFilter->getFBO()->getImageFromPBO();
        } else {
            pBmp = m_pFBO->getImageFromPBO();
        }
        sendFrameToEncoder(pBmp);
        m_bFramePending = false;
    }
}

void VideoWriter::sendFrameToEncoder(BitmapPtr pBitmap)
{
    m_CurFrame++;
    m_bHasValidData = true;
    if (m_pFilter) {
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::encodeYUVFrame, _1, pBitmap));
    } else {
        m_CmdQueue.pushCmd(boost::bind(&VideoWriterThread::encodeFrame, _1, pBitmap));
    }
}

void VideoWriter::onPlaybackEnd()
{
    stop();
}

void VideoWriter::writeDummyFrame()
{
    BitmapPtr pBmp = BitmapPtr(new Bitmap(m_FrameSize, B8G8R8X8));
    FilterFill<Pixel32>(Pixel32(0,0,0,255)).applyInPlace(pBmp);
    sendFrameToEncoder(pBmp);
}

}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// Name:      managedframe.cpp
// Purpose:   Implementation of wxExManagedFrame class.
// Author:    Anton van Wezenbeek
// Created:   2010-04-11
// RCS-ID:    $Id$
// Copyright: (c) 2010 Anton van Wezenbeek
////////////////////////////////////////////////////////////////////////////////

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/extension/managedframe.h>
#include <wx/extension/frd.h>
#include <wx/extension/stc.h>
#include <wx/extension/toolbar.h>
#include <wx/extension/util.h>
#include <wx/extension/vi.h>

#if wxUSE_GUI

// Support class.
// Offers a text ctrl related to a vi object.
class wxExTextCtrl: public wxTextCtrl
{
public:
  /// Constructor. Fills the combobox box with values
  /// from FindReplace from config.
  wxExTextCtrl(
    wxWindow* parent,
    wxExManagedFrame* frame,
    wxStaticText* text,
    wxWindowID id = wxID_ANY,
    const wxPoint& pos = wxDefaultPosition,
    const wxSize& size = wxDefaultSize);

  /// Sets callback.
  void SetVi(wxExVi* vi) {m_vi = vi;};
private:
  void OnCommand(wxCommandEvent& event);
  void OnKey(wxKeyEvent& event);

  wxExManagedFrame* m_Frame;
  wxExVi* m_vi;
  wxStaticText* m_StaticText;

  DECLARE_EVENT_TABLE()
};

#if wxUSE_AUI
BEGIN_EVENT_TABLE(wxExManagedFrame, wxExFrame)
  EVT_MENU(wxID_PREFERENCES, wxExManagedFrame::OnCommand)
  EVT_MENU_RANGE(ID_VIEW_LOWEST, ID_VIEW_HIGHEST, wxExManagedFrame::OnCommand)
  EVT_UPDATE_UI_RANGE(
    ID_VIEW_LOWEST, ID_VIEW_HIGHEST, wxExManagedFrame::OnUpdateUI)
END_EVENT_TABLE()

wxExManagedFrame::wxExManagedFrame(wxWindow* parent,
  wxWindowID id,
  const wxString& title,
  long style)
  : wxExFrame(parent, id, title, style)
{
  m_Manager.SetManagedWindow(this);

  wxExToolBar* toolBar = new wxExToolBar(this);

  toolBar->AddControls();

  DoAddControl(toolBar);

  m_Manager.AddPane(toolBar,
    wxAuiPaneInfo().Top().ToolbarPane().Name("TOOLBAR").Caption(_("Toolbar")));

  m_Manager.AddPane(new wxExFindToolBar(this),
    wxAuiPaneInfo().Bottom().ToolbarPane().Name("FINDBAR").Caption(_("Findbar")));

  CreateViPanel(m_viFindPrefix, m_viFind, "VIFINDBAR");
  CreateViPanel(m_viCommandPrefix, m_viCommand, "VICOMMANDBAR");
}

wxExManagedFrame::~wxExManagedFrame()
{
  m_Manager.UnInit();
}

void wxExManagedFrame::CreateViPanel(
  wxStaticText*& statictext,
  wxExTextCtrl*& text,
  const wxString& name)
{
  wxPanel* panel = new wxPanel(this);

  wxFlexGridSizer* sizer = new wxFlexGridSizer(2);
  statictext = new wxStaticText(panel, wxID_ANY, wxEmptyString);
  text = new wxExTextCtrl(panel, this, statictext);

  sizer->AddGrowableCol(1);
  sizer->Add(statictext, wxSizerFlags().Expand());
  sizer->Add(text, wxSizerFlags().Expand());

  panel->SetSizerAndFit(sizer);

  m_Manager.AddPane(panel,
    wxAuiPaneInfo().Bottom().Floatable(false).Resizable(false).Fixed().Hide().
      Name(name).CaptionVisible(false));
}

void wxExManagedFrame::GetViCommand(wxExVi* vi, const wxString& command)
{
  if (command == ":")
  {
    GetViPaneCommand(m_viCommandPrefix, m_viCommand, "VICOMMANDBAR", vi, command);
  }
  else
  {
    // sync with frd data.
    m_viFind->SetValue(wxExFindReplaceData::Get()->GetFindString());

    GetViPaneCommand(m_viFindPrefix, m_viFind, "VIFINDBAR", vi, command);
  }

  m_Manager.Update();
}

void wxExManagedFrame::GetViPaneCommand(
  wxStaticText* statictext,
  wxExTextCtrl* text,
  const wxString& pane,
  wxExVi* vi,
  const wxString& command)
{
  statictext->SetLabel(command);

  text->Show();
  text->SelectAll();
  text->SetFocus();
  text->SetVi(vi);

  m_Manager.GetPane(pane).Show();
}

void wxExManagedFrame::HideViBar()
{
  if (m_Manager.GetPane("VIFINDBAR").IsShown())
  {
    m_Manager.GetPane("VIFINDBAR").Hide();
    m_Manager.Update();
  }

  if (m_Manager.GetPane("VICOMMANDBAR").IsShown())
  {
    m_Manager.GetPane("VICOMMANDBAR").Hide();
    m_Manager.Update();
  }
}

void wxExManagedFrame::OnCommand(wxCommandEvent& event)
{
  switch (event.GetId())
  {
    case wxID_PREFERENCES:
      wxExSTC::ConfigDialog(this,
        _("Editor Options"),
        wxExSTC::STC_CONFIG_MODELESS |
        wxExSTC::STC_CONFIG_SIMPLE |
        wxExSTC::STC_CONFIG_WITH_APPLY,
        event.GetId());
    break;

    case ID_VIEW_FINDBAR: TogglePane("FINDBAR"); break;
    case ID_VIEW_TOOLBAR: TogglePane("TOOLBAR"); break;

    default:
      wxFAIL;
  }
}

void wxExManagedFrame::OnUpdateUI(wxUpdateUIEvent& event)
{
  switch (event.GetId())
  {
    case ID_VIEW_FINDBAR:
      event.Check(m_Manager.GetPane("FINDBAR").IsShown());
    break;

    case ID_VIEW_TOOLBAR:
      event.Check(m_Manager.GetPane("TOOLBAR").IsShown());
    break;

    default:
      wxFAIL;
  }
}

void wxExManagedFrame::ShowViMessage(const wxString& text)
{
  if (GetStatusBar()->IsShown())
  {
    GetStatusBar()->SetStatusText(text);
  }
  else
  {
    m_viCommandPrefix->SetLabel(text);
    m_viCommand->Hide();

    m_Manager.GetPane("VIFINDBAR").Hide();
    m_Manager.GetPane("VICOMMANDBAR").Show();
    m_Manager.Update();
  }
}

void wxExManagedFrame::TogglePane(const wxString& pane)
{
  wxAuiPaneInfo& info = m_Manager.GetPane(pane);

  wxASSERT(info.IsOk());

  info.IsShown() ? info.Hide(): info.Show();

  m_Manager.Update();
}
#endif // wxUSE_AUI

// Implementation of support class.

BEGIN_EVENT_TABLE(wxExTextCtrl, wxTextCtrl)
  EVT_CHAR(wxExTextCtrl::OnKey)
  EVT_TEXT_ENTER(wxID_ANY, wxExTextCtrl::OnCommand)
END_EVENT_TABLE()

wxExTextCtrl::wxExTextCtrl(
  wxWindow* parent,
  wxExManagedFrame* frame,
  wxStaticText* text,
  wxWindowID id,
  const wxPoint& pos,
  const wxSize& size)
  : wxTextCtrl(parent, id, wxEmptyString, pos, size, wxTE_PROCESS_ENTER)
  , m_Frame(frame)
  , m_vi(NULL)
  , m_StaticText(text)
{
}

void wxExTextCtrl::OnCommand(wxCommandEvent& event)
{
  if (m_StaticText->GetLabel() == ":")
  {
    if (m_vi->ExecCommand(GetValue()))
    {
      m_Frame->HideViBar();
      m_vi->SetFocus();
    }
  }
  else
  {
    if (m_vi->FindCommand(m_StaticText->GetLabel(), GetValue()))
    {
      m_Frame->HideViBar();
      m_vi->SetFocus();
    }
  }
}

void wxExTextCtrl::OnKey(wxKeyEvent& event)
{
  const auto key = event.GetKeyCode();

  if (key == WXK_ESCAPE)
  {
    if (m_vi != NULL)
    {
      m_Frame->HideViBar();
      m_vi->SetFocus();
    }
  }
  else
  {
    event.Skip();
  }
}

#endif // wxUSE_GUI
<commit_msg>removed Fixed, etc., as vi bar does not expand<commit_after>////////////////////////////////////////////////////////////////////////////////
// Name:      managedframe.cpp
// Purpose:   Implementation of wxExManagedFrame class.
// Author:    Anton van Wezenbeek
// Created:   2010-04-11
// RCS-ID:    $Id$
// Copyright: (c) 2010 Anton van Wezenbeek
////////////////////////////////////////////////////////////////////////////////

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/extension/managedframe.h>
#include <wx/extension/frd.h>
#include <wx/extension/stc.h>
#include <wx/extension/toolbar.h>
#include <wx/extension/util.h>
#include <wx/extension/vi.h>

#if wxUSE_GUI

// Support class.
// Offers a text ctrl related to a vi object.
class wxExTextCtrl: public wxTextCtrl
{
public:
  /// Constructor. Fills the combobox box with values
  /// from FindReplace from config.
  wxExTextCtrl(
    wxWindow* parent,
    wxExManagedFrame* frame,
    wxStaticText* text,
    wxWindowID id = wxID_ANY,
    const wxPoint& pos = wxDefaultPosition,
    const wxSize& size = wxDefaultSize);

  /// Sets callback.
  void SetVi(wxExVi* vi) {m_vi = vi;};
private:
  void OnCommand(wxCommandEvent& event);
  void OnKey(wxKeyEvent& event);

  wxExManagedFrame* m_Frame;
  wxExVi* m_vi;
  wxStaticText* m_StaticText;

  DECLARE_EVENT_TABLE()
};

#if wxUSE_AUI
BEGIN_EVENT_TABLE(wxExManagedFrame, wxExFrame)
  EVT_MENU(wxID_PREFERENCES, wxExManagedFrame::OnCommand)
  EVT_MENU_RANGE(ID_VIEW_LOWEST, ID_VIEW_HIGHEST, wxExManagedFrame::OnCommand)
  EVT_UPDATE_UI_RANGE(
    ID_VIEW_LOWEST, ID_VIEW_HIGHEST, wxExManagedFrame::OnUpdateUI)
END_EVENT_TABLE()

wxExManagedFrame::wxExManagedFrame(wxWindow* parent,
  wxWindowID id,
  const wxString& title,
  long style)
  : wxExFrame(parent, id, title, style)
{
  m_Manager.SetManagedWindow(this);

  wxExToolBar* toolBar = new wxExToolBar(this);

  toolBar->AddControls();

  DoAddControl(toolBar);

  m_Manager.AddPane(toolBar,
    wxAuiPaneInfo().Top().ToolbarPane().Name("TOOLBAR").Caption(_("Toolbar")));

  m_Manager.AddPane(new wxExFindToolBar(this),
    wxAuiPaneInfo().Bottom().ToolbarPane().Name("FINDBAR").Caption(_("Findbar")));

  CreateViPanel(m_viFindPrefix, m_viFind, "VIFINDBAR");
  CreateViPanel(m_viCommandPrefix, m_viCommand, "VICOMMANDBAR");
}

wxExManagedFrame::~wxExManagedFrame()
{
  m_Manager.UnInit();
}

void wxExManagedFrame::CreateViPanel(
  wxStaticText*& statictext,
  wxExTextCtrl*& text,
  const wxString& name)
{
  wxPanel* panel = new wxPanel(this);

  wxFlexGridSizer* sizer = new wxFlexGridSizer(2);
  statictext = new wxStaticText(panel, wxID_ANY, wxEmptyString);
  text = new wxExTextCtrl(panel, this, statictext);

  sizer->AddGrowableCol(1);
  sizer->Add(statictext, wxSizerFlags().Expand());
  sizer->Add(text, wxSizerFlags().Expand());

  panel->SetSizerAndFit(sizer);

  m_Manager.AddPane(panel,
    wxAuiPaneInfo().Bottom().Floatable(false).Hide().
      Name(name).CaptionVisible(false));
}

void wxExManagedFrame::GetViCommand(wxExVi* vi, const wxString& command)
{
  if (command == ":")
  {
    GetViPaneCommand(m_viCommandPrefix, m_viCommand, "VICOMMANDBAR", vi, command);
  }
  else
  {
    // sync with frd data.
    m_viFind->SetValue(wxExFindReplaceData::Get()->GetFindString());

    GetViPaneCommand(m_viFindPrefix, m_viFind, "VIFINDBAR", vi, command);
  }

  m_Manager.Update();
}

void wxExManagedFrame::GetViPaneCommand(
  wxStaticText* statictext,
  wxExTextCtrl* text,
  const wxString& pane,
  wxExVi* vi,
  const wxString& command)
{
  statictext->SetLabel(command);

  text->Show();
  text->SelectAll();
  text->SetFocus();
  text->SetVi(vi);

  m_Manager.GetPane(pane).Show();
}

void wxExManagedFrame::HideViBar()
{
  if (m_Manager.GetPane("VIFINDBAR").IsShown())
  {
    m_Manager.GetPane("VIFINDBAR").Hide();
    m_Manager.Update();
  }

  if (m_Manager.GetPane("VICOMMANDBAR").IsShown())
  {
    m_Manager.GetPane("VICOMMANDBAR").Hide();
    m_Manager.Update();
  }
}

void wxExManagedFrame::OnCommand(wxCommandEvent& event)
{
  switch (event.GetId())
  {
    case wxID_PREFERENCES:
      wxExSTC::ConfigDialog(this,
        _("Editor Options"),
        wxExSTC::STC_CONFIG_MODELESS |
        wxExSTC::STC_CONFIG_SIMPLE |
        wxExSTC::STC_CONFIG_WITH_APPLY,
        event.GetId());
    break;

    case ID_VIEW_FINDBAR: TogglePane("FINDBAR"); break;
    case ID_VIEW_TOOLBAR: TogglePane("TOOLBAR"); break;

    default:
      wxFAIL;
  }
}

void wxExManagedFrame::OnUpdateUI(wxUpdateUIEvent& event)
{
  switch (event.GetId())
  {
    case ID_VIEW_FINDBAR:
      event.Check(m_Manager.GetPane("FINDBAR").IsShown());
    break;

    case ID_VIEW_TOOLBAR:
      event.Check(m_Manager.GetPane("TOOLBAR").IsShown());
    break;

    default:
      wxFAIL;
  }
}

void wxExManagedFrame::ShowViMessage(const wxString& text)
{
  if (GetStatusBar()->IsShown())
  {
    GetStatusBar()->SetStatusText(text);
  }
  else
  {
    m_viCommandPrefix->SetLabel(text);
    m_viCommand->Hide();

    m_Manager.GetPane("VIFINDBAR").Hide();
    m_Manager.GetPane("VICOMMANDBAR").Show();
    m_Manager.Update();
  }
}

void wxExManagedFrame::TogglePane(const wxString& pane)
{
  wxAuiPaneInfo& info = m_Manager.GetPane(pane);

  wxASSERT(info.IsOk());

  info.IsShown() ? info.Hide(): info.Show();

  m_Manager.Update();
}
#endif // wxUSE_AUI

// Implementation of support class.

BEGIN_EVENT_TABLE(wxExTextCtrl, wxTextCtrl)
  EVT_CHAR(wxExTextCtrl::OnKey)
  EVT_TEXT_ENTER(wxID_ANY, wxExTextCtrl::OnCommand)
END_EVENT_TABLE()

wxExTextCtrl::wxExTextCtrl(
  wxWindow* parent,
  wxExManagedFrame* frame,
  wxStaticText* text,
  wxWindowID id,
  const wxPoint& pos,
  const wxSize& size)
  : wxTextCtrl(parent, id, wxEmptyString, pos, size, wxTE_PROCESS_ENTER)
  , m_Frame(frame)
  , m_vi(NULL)
  , m_StaticText(text)
{
}

void wxExTextCtrl::OnCommand(wxCommandEvent& event)
{
  if (m_StaticText->GetLabel() == ":")
  {
    if (m_vi->ExecCommand(GetValue()))
    {
      m_Frame->HideViBar();
      m_vi->SetFocus();
    }
  }
  else
  {
    if (m_vi->FindCommand(m_StaticText->GetLabel(), GetValue()))
    {
      m_Frame->HideViBar();
      m_vi->SetFocus();
    }
  }
}

void wxExTextCtrl::OnKey(wxKeyEvent& event)
{
  const auto key = event.GetKeyCode();

  if (key == WXK_ESCAPE)
  {
    if (m_vi != NULL)
    {
      m_Frame->HideViBar();
      m_vi->SetFocus();
    }
  }
  else
  {
    event.Skip();
  }
}

#endif // wxUSE_GUI
<|endoftext|>


<commit_before>//+ Example on the  usage of the adaptive 1D integration algorithm of MathMore
// it calculates the numerically cumulative integral of a distribution (like in this case the BreitWigner)
// to execute the macro type it (you need to compile with AClic)
//
// root[0]: .x mathmoreIntegration.C+
//
// This tutorials require having libMathMore built with ROOT.
//
// To build mathmore you need to have a version of GSL >= 1.8 installed in your system
// The ROOT configure will automatically find GSL if the script gsl-config (from GSL) is in your PATH,.
// otherwise you need to configure root with the options --gsl-incdir and --gsl-libdir.
//
//
// Authors: M. Slawinska and L. Moneta

#include "TMath.h"
#include "TH1.h"
#include "TCanvas.h"
#include "TLegend.h"

//#include "TLabel.h"
#include "Math/Functor.h"
#include "Math/WrappedFunction.h"
#include "Math/IFunction.h"
#include "Math/Integrator.h"
#include <iostream>

#include "TStopwatch.h"
#include "TF1.h"

#include <limits>

//!calculates exact integral of Breit Wigner distribution
//!and compares with existing methods

int nc = 0;
double exactIntegral( double a, double b) {

  return (TMath::ATan(2*b)- TMath::ATan(2*a))/ TMath::Pi();
}
double func( double x){
   nc++;
   return TMath::BreitWigner(x);
}
// TF1 requires the function to have the ( )( double *, double *) signature
double func2(const double *x, const double * = 0){
   nc++;
   return TMath::BreitWigner(x[0]);
}

void  testIntegPerf(double x1, double x2, int n = 100000){

   std::cout << "\n\n***************************************************************\n";
   std::cout << "Test integration performances in interval [ " << x1 << " , " << x2 << " ]\n\n";

  TStopwatch timer;

  double dx = (x2-x1)/double(n);

  //ROOT::Math::Functor1D<ROOT::Math::IGenFunction> f1(& TMath::BreitWigner);
  ROOT::Math::WrappedFunction<> f1(func);

  timer.Start();
  ROOT::Math::Integrator ig(f1 );
  double s1 = 0.0;
  nc = 0;
  for (int i = 0; i < n; ++i) {
     double x = x1 + dx*i;
     s1+= ig.Integral(x1,x);
  }
  timer.Stop();
  std::cout << "Time using ROOT::Math::Integrator        :\t" << timer.RealTime() << std::endl;
  std::cout << "Number of function calls = " << nc/n << std::endl;
  int pr = std::cout.precision(18);  std::cout << s1 << std::endl;  std::cout.precision(pr);

  //TF1 *fBW = new TF1("fBW","TMath::BreitWigner(x)",x1, x2);  //  this is faster but cannot measure number of function calls
  TF1 *fBW = new TF1("fBW",func2,x1, x2,0);

  timer.Start();
  nc = 0;
  double s2 = 0;
  for (int i = 0; i < n; ++i) {
     double x = x1 + dx*i;
     s2+= fBW->Integral(x1,x );
  }
  timer.Stop();
  std::cout << "Time using TF1::Integral :\t\t\t" << timer.RealTime() << std::endl;
  std::cout << "Number of function calls = " << nc/n << std::endl;
  pr = std::cout.precision(18);  std::cout << s1 << std::endl;  std::cout.precision(pr);

}

void  DrawCumulative(double x1, double x2, int n = 100){

   std::cout << "\n\n***************************************************************\n";
   std::cout << "Drawing cumulatives of BreitWigner in interval [ " << x1 << " , " << x2 << " ]\n\n";

   double dx = (x2-x1)/double(n);

   TH1D *cum0 = new TH1D("cum0", "", n, x1, x2); //exact cumulative
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum0->SetBinContent(i, exactIntegral(x1, x));

   }

   // alternative method using ROOT::Math::Functor class
   ROOT::Math::Functor1D f1(& func);

   ROOT::Math::Integrator ig(f1, ROOT::Math::IntegrationOneDim::kADAPTIVE,1.E-12,1.E-12);

   TH1D *cum1 = new TH1D("cum1", "", n, x1, x2);
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum1->SetBinContent(i, ig.Integral(x1,x));
   }

   TF1 *fBW = new TF1("fBW","TMath::BreitWigner(x, 0, 1)",x1, x2);

   TH1D *cum2 = new TH1D("cum2", "", n, x1, x2);
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum2->SetBinContent(i, fBW->Integral(x1,x));
   }

   TH1D *cum10 = new TH1D("cum10", "", n, x1, x2); //difference between  1 and exact
   TH1D *cum20 = new TH1D("cum23", "", n, x1, x2); //difference between 2 and excact
   for (int i = 1; i <= n; ++i) {
      double delta  =  cum1->GetBinContent(i) - cum0->GetBinContent(i);
      double delta2 =  cum2->GetBinContent(i) - cum0->GetBinContent(i);
      //std::cout << " diff for " << x << " is " << delta << "  " << cum1->GetBinContent(i) << std::endl;
      cum10->SetBinContent(i, delta );
      cum10->SetBinError(i, std::numeric_limits<double>::epsilon() * cum1->GetBinContent(i) );
      cum20->SetBinContent(i, delta2 );
   }

   TCanvas *c1 = new TCanvas("c1","Integration example",20,10,800,500);
   c1->Divide(2,1);
   c1->Draw();

   cum0->SetLineColor(kBlack);
   cum0->SetTitle("BreitWigner - the cumulative");
   cum0->SetStats(0);
   cum1->SetLineStyle(2);
   cum2->SetLineStyle(3);
   cum1->SetLineColor(kBlue);
   cum2->SetLineColor(kRed);
   c1->cd(1);
   cum0->DrawCopy("h");
   cum1->DrawCopy("same");
   //cum2->DrawCopy("same");
   cum2->DrawCopy("same");

   c1->cd(2);
   cum10->SetTitle("Difference");
   cum10->SetStats(0);
   cum10->SetLineColor(kBlue);
   cum10->Draw("e0");
   cum20->SetLineColor(kRed);
   cum20->Draw("hsame");

   TLegend * l = new TLegend(0.11, 0.8, 0.7 ,0.89);
   l->AddEntry(cum10, "GSL integration - analytical ");
   l->AddEntry(cum20, "TF1::Integral  - analytical ");
   l->Draw();

   c1->Update();
   std::cout << "\n***************************************************************\n";

}

void mathmoreIntegration(double a = -2, double b = 2)
{

   DrawCumulative(a, b);
   testIntegPerf(a, b);
}

<commit_msg>add message that tutorial can be run only using AClic<commit_after>//+ Example on the  usage of the adaptive 1D integration algorithm of MathMore
// it calculates the numerically cumulative integral of a distribution (like in this case the BreitWigner)
// to execute the macro type it (you need to compile with AClic)
//
// root[0]: .x mathmoreIntegration.C+
//
// This tutorials require having libMathMore built with ROOT.
//
// To build mathmore you need to have a version of GSL >= 1.8 installed in your system
// The ROOT configure will automatically find GSL if the script gsl-config (from GSL) is in your PATH,.
// otherwise you need to configure root with the options --gsl-incdir and --gsl-libdir.
//
//
// Authors: M. Slawinska and L. Moneta

#include "TMath.h"
#include "TH1.h"
#include "TCanvas.h"
#include "TLegend.h"

//#include "TLabel.h"
#include "Math/Functor.h"
#include "Math/WrappedFunction.h"
#include "Math/IFunction.h"
#include "Math/Integrator.h"
#include <iostream>

#include "TStopwatch.h"
#include "TF1.h"

#include <limits>

//!calculates exact integral of Breit Wigner distribution
//!and compares with existing methods

int nc = 0;
double exactIntegral( double a, double b) {

  return (TMath::ATan(2*b)- TMath::ATan(2*a))/ TMath::Pi();
}
double func( double x){
   nc++;
   return TMath::BreitWigner(x);
}
// TF1 requires the function to have the ( )( double *, double *) signature
double func2(const double *x, const double * = 0){
   nc++;
   return TMath::BreitWigner(x[0]);
}

void  testIntegPerf(double x1, double x2, int n = 100000){

   std::cout << "\n\n***************************************************************\n";
   std::cout << "Test integration performances in interval [ " << x1 << " , " << x2 << " ]\n\n";

  TStopwatch timer;

  double dx = (x2-x1)/double(n);

  //ROOT::Math::Functor1D<ROOT::Math::IGenFunction> f1(& TMath::BreitWigner);
  ROOT::Math::WrappedFunction<> f1(func);

  timer.Start();
  ROOT::Math::Integrator ig(f1 );
  double s1 = 0.0;
  nc = 0;
  for (int i = 0; i < n; ++i) {
     double x = x1 + dx*i;
     s1+= ig.Integral(x1,x);
  }
  timer.Stop();
  std::cout << "Time using ROOT::Math::Integrator        :\t" << timer.RealTime() << std::endl;
  std::cout << "Number of function calls = " << nc/n << std::endl;
  int pr = std::cout.precision(18);  std::cout << s1 << std::endl;  std::cout.precision(pr);

  //TF1 *fBW = new TF1("fBW","TMath::BreitWigner(x)",x1, x2);  //  this is faster but cannot measure number of function calls
  TF1 *fBW = new TF1("fBW",func2,x1, x2,0);

  timer.Start();
  nc = 0;
  double s2 = 0;
  for (int i = 0; i < n; ++i) {
     double x = x1 + dx*i;
     s2+= fBW->Integral(x1,x );
  }
  timer.Stop();
  std::cout << "Time using TF1::Integral :\t\t\t" << timer.RealTime() << std::endl;
  std::cout << "Number of function calls = " << nc/n << std::endl;
  pr = std::cout.precision(18);  std::cout << s1 << std::endl;  std::cout.precision(pr);

}

void  DrawCumulative(double x1, double x2, int n = 100){

   std::cout << "\n\n***************************************************************\n";
   std::cout << "Drawing cumulatives of BreitWigner in interval [ " << x1 << " , " << x2 << " ]\n\n";

   double dx = (x2-x1)/double(n);

   TH1D *cum0 = new TH1D("cum0", "", n, x1, x2); //exact cumulative
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum0->SetBinContent(i, exactIntegral(x1, x));

   }

   // alternative method using ROOT::Math::Functor class
   ROOT::Math::Functor1D f1(& func);

   ROOT::Math::Integrator ig(f1, ROOT::Math::IntegrationOneDim::kADAPTIVE,1.E-12,1.E-12);

   TH1D *cum1 = new TH1D("cum1", "", n, x1, x2);
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum1->SetBinContent(i, ig.Integral(x1,x));
   }

   TF1 *fBW = new TF1("fBW","TMath::BreitWigner(x, 0, 1)",x1, x2);

   TH1D *cum2 = new TH1D("cum2", "", n, x1, x2);
   for (int i = 1; i <= n; ++i) {
      double x = x1 + dx*i;
      cum2->SetBinContent(i, fBW->Integral(x1,x));
   }

   TH1D *cum10 = new TH1D("cum10", "", n, x1, x2); //difference between  1 and exact
   TH1D *cum20 = new TH1D("cum23", "", n, x1, x2); //difference between 2 and excact
   for (int i = 1; i <= n; ++i) {
      double delta  =  cum1->GetBinContent(i) - cum0->GetBinContent(i);
      double delta2 =  cum2->GetBinContent(i) - cum0->GetBinContent(i);
      //std::cout << " diff for " << x << " is " << delta << "  " << cum1->GetBinContent(i) << std::endl;
      cum10->SetBinContent(i, delta );
      cum10->SetBinError(i, std::numeric_limits<double>::epsilon() * cum1->GetBinContent(i) );
      cum20->SetBinContent(i, delta2 );
   }

   TCanvas *c1 = new TCanvas("c1","Integration example",20,10,800,500);
   c1->Divide(2,1);
   c1->Draw();

   cum0->SetLineColor(kBlack);
   cum0->SetTitle("BreitWigner - the cumulative");
   cum0->SetStats(0);
   cum1->SetLineStyle(2);
   cum2->SetLineStyle(3);
   cum1->SetLineColor(kBlue);
   cum2->SetLineColor(kRed);
   c1->cd(1);
   cum0->DrawCopy("h");
   cum1->DrawCopy("same");
   //cum2->DrawCopy("same");
   cum2->DrawCopy("same");

   c1->cd(2);
   cum10->SetTitle("Difference");
   cum10->SetStats(0);
   cum10->SetLineColor(kBlue);
   cum10->Draw("e0");
   cum20->SetLineColor(kRed);
   cum20->Draw("hsame");

   TLegend * l = new TLegend(0.11, 0.8, 0.7 ,0.89);
   l->AddEntry(cum10, "GSL integration - analytical ");
   l->AddEntry(cum20, "TF1::Integral  - analytical ");
   l->Draw();

   c1->Update();
   std::cout << "\n***************************************************************\n";

}

void mathmoreIntegration(double a = -2, double b = 2)
{
#if defined(__CINT__) && !defined(__MAKECINT__)
  cout << "WARNING: This tutorial can run only using ACliC, you must run it by doing: " << endl;
  cout << "\t .x $ROOTSYS/tutorials/math/mathmoreIntegration.C+" << endl;
  return;
#endif

   DrawCumulative(a, b);
   testIntegPerf(a, b);
}

<|endoftext|>


<commit_before>#include "Main.h"

//获取基本信息
void handlerGetDeviceBaseInfo(struct bufferevent * bufEvent,Json::Value &data){
    char buffer[100];
    //获取内存大小
    struct sysinfo memInfo;
    sysinfo(&memInfo);
    //获取磁盘大小
    struct statfs diskInfo;
    statfs(DISK_SIZE_PATH, &diskInfo);
    //格式化数据
    double totalMemSize = (double)memInfo.totalram/(1024.0*1024.0);
    double usedMemSize = (double)(memInfo.totalram-memInfo.freeram)/(1024.0*1024.0);
    double totalDiskSize = (double)(diskInfo.f_bsize*diskInfo.f_blocks)/(1024.0*1024.0);
    double usedDiskSize = (double)(diskInfo.f_bsize*diskInfo.f_blocks-diskInfo.f_bsize*diskInfo.f_bfree)/(1024.0*1024.0);
    //构造返回JSON
    Json::Value root;
    Json::Value re_data;
    root["is_app"] = false;
    root["protocol"] = API_DEVICE_BASE_INFO;
    //总内存大小
    sprintf(buffer,"%.2f",totalMemSize);
    re_data["mem_total"] = string(buffer);
    memset(buffer,0,100);
    //使用内存
    sprintf(buffer,"%.2f",usedMemSize);
    re_data["mem_used"] = string(buffer);
    memset(buffer,0,100);
    //总硬盘大小
    sprintf(buffer,"%.2f",totalDiskSize);
    re_data["disk_total"] = string(buffer);
    memset(buffer,0,100);
    //使用硬盘大小
    sprintf(buffer,"%.2f",usedDiskSize);
    re_data["disk_used"] = string(buffer);
    memset(buffer,0,100);
    //返回数据
    root["data"] = re_data;
    bufferevent_write(bufEvent, root.toStyledString().c_str(), root.toStyledString().length());
}
void setCameraPower(struct bufferevent * bufEvent,Json::Value &data){
    printf("SetCameraPower:%s\n",data.toStyledString().c_str() );
}
//键盘按下
void handlerKeyDown(struct bufferevent * bufEvent,Json::Value &data){
    Json::Value key_map = data["data"];
    int key = atoi(key_map["key"].asString().c_str());
    switch(key){
        case 119://W
        case 115://S
        case 97://A
        case 100://D
        case 105://I
        case 107://K
        case 106://J
        case 108://L
            printf("key down:%d\n", key);
        break;
        default:
            printf("key not find:%d\n", key);
        break;
    }
}
//获取MAC地址
string getMacAddress(){
    char buff[32];
    memset (buff ,'\0', sizeof(buff));
    string cmd = "ip addr |grep -A 2 "+network_card_name+" | awk 'NR>1'|awk 'NR<2'|awk '{print $2}'";
    // 通过管道来回去系统命令返回的值
    FILE *fstream = popen(cmd.c_str(), "r");
    if(fstream == NULL) {
        perror("popen");
        exit(0);
    }
    if(NULL == fgets(buff, sizeof(buff), fstream)){
        printf("not find mac address !!!\n");
        exit(0);
    }
    pclose(fstream);
    string mac;
    mac = string(buff);
    mac = mac.substr(0, mac.length()-1);
    return mac;
}
//调用方法
void callFunc(struct bufferevent * bufEvent,Json::Value &request_data,const string func){
    if(func.length() == 0){
        return;
    }
    if (client_api_list.count(func)) {
        (*(client_api_list[func]))(bufEvent,request_data);
    }
}

void sendDeviceInfo(struct bufferevent * bufEvent){
    Json::Value root;
    Json::Value data;
    //获取MAC地址
    data["mac"] = getMacAddress();
    data["name"] = device_name;
    root["protocol"] = API_DEVICE_INFO;
    root["is_app"] = false;
    root["data"] = data;
    string json = root.toStyledString();
    bufferevent_write(bufEvent, json.c_str(), json.length());
}

//读操作
void ReadEventCb(struct bufferevent *bufEvent, void *args){
   Json::Reader reader;
    Json::Value data;
    //获取输入缓存
    struct evbuffer * pInput = bufferevent_get_input(bufEvent);
    //获取输入缓存数据的长度
    int len = evbuffer_get_length(pInput);
    //获取数据
    char* body = new char[len+1];
    memset(body,0,sizeof(char)*(len+1));
    evbuffer_remove(pInput, body, len);
    if(reader.parse(body, data)){
        string func = data["protocol"].asString();
        callFunc(bufEvent,data,func);
    }
    delete[] body;
    return ;
}
//写操作
void WriteEventCb(struct bufferevent *bufEvent, void *args){

}
//关闭
void SignalEventCb(struct bufferevent * bufEvent, short sEvent, void * args){
    //请求的连接过程已经完成
    if(BEV_EVENT_CONNECTED == sEvent){
        bufferevent_enable(bufEvent, EV_READ);
        //设置读超时时间 10s
        struct timeval tTimeout = {10, 0};
        bufferevent_set_timeouts( bufEvent, &tTimeout, NULL);
        string mac = getMacAddress();
        if(mac.length() == 0){
            printf("MAC地址获取错误请检查网卡配置\n");
            event_base_loopexit(baseEvent, NULL);
            exit(0);
        }
        //发送基本信息
        sendDeviceInfo(bufEvent);
    }
    //写操作发生事件
    if(BEV_EVENT_WRITING & sEvent){}
    //操作时发生错误
    if (sEvent & BEV_EVENT_ERROR){
        perror("event");
        event_base_loopexit(baseEvent, NULL);
    }
    //结束指示
    if (sEvent & BEV_EVENT_EOF){
        perror("event");
        event_base_loopexit(baseEvent, NULL);
    }
    //读取发生事件或者超时处理
    if(0 != (sEvent & (BEV_EVENT_TIMEOUT|BEV_EVENT_READING)) ){
        //发送心跳包
        //
        //重新注册可读事件
        bufferevent_enable(bufEvent, EV_READ);
    }
    return ;
}
//设置配置文件
void setConfig(const char* config_path){
    Config config;
    //检测配置文件是否存在
    if(!config.FileExist(config_path)){
      printf("config: not find config file\n");
      exit(0);
    }
    //读取配置
    config.ReadFile(config_path);
    api_host = config.Read("SERVER_HOST", api_host);
    api_port = config.Read("API_PORT", api_port);
    network_card_name = config.Read("NETWORK_CARD", network_card_name);
    device_name = config.Read("DEVICE_NAME", device_name);
}
//开始
void startRun(const char* ip,int port){
    //创建事件驱动句柄
    baseEvent = event_base_new();
    //创建socket类型的bufferevent
    struct bufferevent* bufferEvent = bufferevent_socket_new(baseEvent, -1, 0);
    //构造服务器地址
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(api_host.c_str());
    sin.sin_port = htons(api_port);
    //连接服务器
    if( bufferevent_socket_connect(bufferEvent, (struct sockaddr*)&sin, sizeof(sin)) < 0){
        perror("socket");
        return;
    }
    //设置回调函数, 及回调函数的参数
    bufferevent_setcb(bufferEvent, ReadEventCb, WriteEventCb, SignalEventCb,NULL);
    //开始事件循环
    event_base_dispatch(baseEvent);
    //事件循环结束 资源清理
    bufferevent_free(bufferEvent);
    event_base_free(baseEvent);
}
//初始化API列表
void initApiList() {
  client_api_list[API_DEVICE_BASE_INFO] = &handlerGetDeviceBaseInfo;
  client_api_list[API_DEVICE_KEY_DOWN] = &handlerKeyDown;
  client_api_list[API_SET_CAMERA_POWER] = &setCameraPower
}

int main(){
    //加载API列表
    initApiList();
    //加载配置文件
    setConfig(CONFIG_PATH);
    //启动sockt
    startRun(api_host.c_str(),api_port);
    return 0;
}
<commit_msg>添加设置相机开关<commit_after>#include "Main.h"

//获取基本信息
void handlerGetDeviceBaseInfo(struct bufferevent * bufEvent,Json::Value &data){
    char buffer[100];
    //获取内存大小
    struct sysinfo memInfo;
    sysinfo(&memInfo);
    //获取磁盘大小
    struct statfs diskInfo;
    statfs(DISK_SIZE_PATH, &diskInfo);
    //格式化数据
    double totalMemSize = (double)memInfo.totalram/(1024.0*1024.0);
    double usedMemSize = (double)(memInfo.totalram-memInfo.freeram)/(1024.0*1024.0);
    double totalDiskSize = (double)(diskInfo.f_bsize*diskInfo.f_blocks)/(1024.0*1024.0);
    double usedDiskSize = (double)(diskInfo.f_bsize*diskInfo.f_blocks-diskInfo.f_bsize*diskInfo.f_bfree)/(1024.0*1024.0);
    //构造返回JSON
    Json::Value root;
    Json::Value re_data;
    root["is_app"] = false;
    root["protocol"] = API_DEVICE_BASE_INFO;
    //总内存大小
    sprintf(buffer,"%.2f",totalMemSize);
    re_data["mem_total"] = string(buffer);
    memset(buffer,0,100);
    //使用内存
    sprintf(buffer,"%.2f",usedMemSize);
    re_data["mem_used"] = string(buffer);
    memset(buffer,0,100);
    //总硬盘大小
    sprintf(buffer,"%.2f",totalDiskSize);
    re_data["disk_total"] = string(buffer);
    memset(buffer,0,100);
    //使用硬盘大小
    sprintf(buffer,"%.2f",usedDiskSize);
    re_data["disk_used"] = string(buffer);
    memset(buffer,0,100);
    //返回数据
    root["data"] = re_data;
    bufferevent_write(bufEvent, root.toStyledString().c_str(), root.toStyledString().length());
}
void setCameraPower(struct bufferevent * bufEvent,Json::Value &data){
    printf("SetCameraPower:%s\n",data.toStyledString().c_str() );
}
//键盘按下
void handlerKeyDown(struct bufferevent * bufEvent,Json::Value &data){
    Json::Value key_map = data["data"];
    int key = atoi(key_map["key"].asString().c_str());
    switch(key){
        case 119://W
        case 115://S
        case 97://A
        case 100://D
        case 105://I
        case 107://K
        case 106://J
        case 108://L
            printf("key down:%d\n", key);
        break;
        default:
            printf("key not find:%d\n", key);
        break;
    }
}
//获取MAC地址
string getMacAddress(){
    char buff[32];
    memset (buff ,'\0', sizeof(buff));
    string cmd = "ip addr |grep -A 2 "+network_card_name+" | awk 'NR>1'|awk 'NR<2'|awk '{print $2}'";
    // 通过管道来回去系统命令返回的值
    FILE *fstream = popen(cmd.c_str(), "r");
    if(fstream == NULL) {
        perror("popen");
        exit(0);
    }
    if(NULL == fgets(buff, sizeof(buff), fstream)){
        printf("not find mac address !!!\n");
        exit(0);
    }
    pclose(fstream);
    string mac;
    mac = string(buff);
    mac = mac.substr(0, mac.length()-1);
    return mac;
}
//调用方法
void callFunc(struct bufferevent * bufEvent,Json::Value &request_data,const string func){
    if(func.length() == 0){
        return;
    }
    if (client_api_list.count(func)) {
        (*(client_api_list[func]))(bufEvent,request_data);
    }
}

void sendDeviceInfo(struct bufferevent * bufEvent){
    Json::Value root;
    Json::Value data;
    //获取MAC地址
    data["mac"] = getMacAddress();
    data["name"] = device_name;
    root["protocol"] = API_DEVICE_INFO;
    root["is_app"] = false;
    root["data"] = data;
    string json = root.toStyledString();
    bufferevent_write(bufEvent, json.c_str(), json.length());
}

//读操作
void ReadEventCb(struct bufferevent *bufEvent, void *args){
   Json::Reader reader;
    Json::Value data;
    //获取输入缓存
    struct evbuffer * pInput = bufferevent_get_input(bufEvent);
    //获取输入缓存数据的长度
    int len = evbuffer_get_length(pInput);
    //获取数据
    char* body = new char[len+1];
    memset(body,0,sizeof(char)*(len+1));
    evbuffer_remove(pInput, body, len);
    if(reader.parse(body, data)){
        string func = data["protocol"].asString();
        callFunc(bufEvent,data,func);
    }
    delete[] body;
    return ;
}
//写操作
void WriteEventCb(struct bufferevent *bufEvent, void *args){

}
//关闭
void SignalEventCb(struct bufferevent * bufEvent, short sEvent, void * args){
    //请求的连接过程已经完成
    if(BEV_EVENT_CONNECTED == sEvent){
        bufferevent_enable(bufEvent, EV_READ);
        //设置读超时时间 10s
        struct timeval tTimeout = {10, 0};
        bufferevent_set_timeouts( bufEvent, &tTimeout, NULL);
        string mac = getMacAddress();
        if(mac.length() == 0){
            printf("MAC地址获取错误请检查网卡配置\n");
            event_base_loopexit(baseEvent, NULL);
            exit(0);
        }
        //发送基本信息
        sendDeviceInfo(bufEvent);
    }
    //写操作发生事件
    if(BEV_EVENT_WRITING & sEvent){}
    //操作时发生错误
    if (sEvent & BEV_EVENT_ERROR){
        perror("event");
        event_base_loopexit(baseEvent, NULL);
    }
    //结束指示
    if (sEvent & BEV_EVENT_EOF){
        perror("event");
        event_base_loopexit(baseEvent, NULL);
    }
    //读取发生事件或者超时处理
    if(0 != (sEvent & (BEV_EVENT_TIMEOUT|BEV_EVENT_READING)) ){
        //发送心跳包
        //
        //重新注册可读事件
        bufferevent_enable(bufEvent, EV_READ);
    }
    return ;
}
//设置配置文件
void setConfig(const char* config_path){
    Config config;
    //检测配置文件是否存在
    if(!config.FileExist(config_path)){
      printf("config: not find config file\n");
      exit(0);
    }
    //读取配置
    config.ReadFile(config_path);
    api_host = config.Read("SERVER_HOST", api_host);
    api_port = config.Read("API_PORT", api_port);
    network_card_name = config.Read("NETWORK_CARD", network_card_name);
    device_name = config.Read("DEVICE_NAME", device_name);
}
//开始
void startRun(const char* ip,int port){
    //创建事件驱动句柄
    baseEvent = event_base_new();
    //创建socket类型的bufferevent
    struct bufferevent* bufferEvent = bufferevent_socket_new(baseEvent, -1, 0);
    //构造服务器地址
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(api_host.c_str());
    sin.sin_port = htons(api_port);
    //连接服务器
    if( bufferevent_socket_connect(bufferEvent, (struct sockaddr*)&sin, sizeof(sin)) < 0){
        perror("socket");
        return;
    }
    //设置回调函数, 及回调函数的参数
    bufferevent_setcb(bufferEvent, ReadEventCb, WriteEventCb, SignalEventCb,NULL);
    //开始事件循环
    event_base_dispatch(baseEvent);
    //事件循环结束 资源清理
    bufferevent_free(bufferEvent);
    event_base_free(baseEvent);
}
//初始化API列表
void initApiList() {
  client_api_list[API_DEVICE_BASE_INFO] = &handlerGetDeviceBaseInfo;
  client_api_list[API_DEVICE_KEY_DOWN] = &handlerKeyDown;
  client_api_list[API_SET_CAMERA_POWER] = &setCameraPower;
}

int main(){
    //加载API列表
    initApiList();
    //加载配置文件
    setConfig(CONFIG_PATH);
    //启动sockt
    startRun(api_host.c_str(),api_port);
    return 0;
}
<|endoftext|>


<commit_before>/*
   Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
*/

/** Unit test case for the function explain_filename(). */

#include <tap.h>
#include <mysqld_error.h>
#include <sql_class.h>
#include <sql_table.h>

#define BUFLEN 1000
char to[BUFLEN];
char from[BUFLEN];

const char *error_messages[1000];

int setup()
{
  system_charset_info    = &my_charset_utf8_bin;
  my_default_lc_messages = &my_locale_en_US;

  /* Populate the necessary error messages */
  error_messages[ER_DATABASE_NAME - ER_ERROR_FIRST]     = "Database";
  error_messages[ER_TABLE_NAME - ER_ERROR_FIRST]        = "Table";
  error_messages[ER_PARTITION_NAME - ER_ERROR_FIRST]    = "Partition";
  error_messages[ER_SUBPARTITION_NAME - ER_ERROR_FIRST] = "Subpartition";
  error_messages[ER_TEMPORARY_NAME - ER_ERROR_FIRST]    = "Temporary";
  error_messages[ER_RENAMED_NAME - ER_ERROR_FIRST]      = "Renamed";

  my_default_lc_messages->errmsgs->errmsgs = error_messages;

  return 0;
}

void test_1(const char *in, const char *exp, enum_explain_filename_mode mode)
{
  char out[BUFLEN];

  uint len1 = explain_filename(0, in, out, BUFLEN, mode);

  /* expected output and actual output must be same */
  bool pass = (strcmp(exp, out) == 0);

  /* length returned by explain_filename is fine */
  bool length = (len1 == strlen(exp));

  ok( (pass && length) , "(%d): %s => %s\n", mode, in, out);
}

int main()
{
  setup();
  plan(22);

  test_1("test/t1.ibd",
         "Database \"test\", Table \"t1.ibd\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1.ibd",
         "\"test\".\"t1.ibd\"",
         EXPLAIN_PARTITIONS_VERBOSE);

  test_1("test/t1.ibd",
         "\"test\".\"t1.ibd\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#TMP#",
         "Database \"test\", Table \"t1#TMP#\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/#sql-2882.ibd",
         "Database \"test\", Table \"#sql-2882.ibd\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1#REN#",
         "Database \"test\", Table \"t1#REN#\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1@0023REN@0023",
         "Database \"test\", Table \"t1#REN#\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1#p#p1",
         "Database \"test\", Table \"t1\", Partition \"p1\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1#P#p1",
         "\"test\".\"t1\" /* Partition \"p1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#P#p1@00231",
         "\"test\".\"t1\" /* Partition \"p1#1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#P#p1#SP#sp1",
         "\"test\".\"t1\" /* Partition \"p1\", Subpartition \"sp1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#p1#SP#sp1",
         "\"test\".\"t1#p1#SP#sp1\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#p#p1@00232#SP#sp1@00231#REN#",
         "\"test\".\"t1\" /* Renamed Partition \"p1#2\", Subpartition \"sp1#1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#p#p1#SP#sp1#TMP#",
         "\"test\".\"t1\" /* Temporary Partition \"p1\", Subpartition \"sp1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/#sql-t1#P#p1#SP#sp1#TMP#",
         "\"test\".\"#sql-t1#P#p1#SP#sp1#TMP#\" /* Temporary Partition \"p1\", Subpartition \"sp1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/#sql-t1#P#p1#SP#sp1",
         "\"test\".\"#sql-t1#P#p1#SP#sp1\" /* Partition \"p1\", Subpartition \"sp1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/#sqlx-33",
         "\"test\".\"#sqlx-33\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/#mysql50#t",
         "\"test\".\"#mysql50#t\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("#mysql50#t",
         "\"#mysql50#t\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("@0023t",
         "\"#t\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t@0023",
         "\"test\".\"t#\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  /*
    If a character not allowed in my_charset_filename is encountered,
    then it will not be converted to system_charset_info!
  */
  test_1("test/t@0023#",
         "\"test\".\"t@0023#\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  return 0;
}

<commit_msg>Bug #16994338 PARSING TAP OUTPUT OF UNIT TEST EXPLAIN_FILENAME-T FAILS<commit_after>/*
   Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
*/

/** Unit test case for the function explain_filename(). */

#include <tap.h>
#include <mysqld_error.h>
#include <sql_class.h>
#include <sql_table.h>

#define BUFLEN 1000
char to[BUFLEN];
char from[BUFLEN];

const char *error_messages[1000];

int setup()
{
  system_charset_info    = &my_charset_utf8_bin;
  my_default_lc_messages = &my_locale_en_US;

  /* Populate the necessary error messages */
  error_messages[ER_DATABASE_NAME - ER_ERROR_FIRST]     = "Database";
  error_messages[ER_TABLE_NAME - ER_ERROR_FIRST]        = "Table";
  error_messages[ER_PARTITION_NAME - ER_ERROR_FIRST]    = "Partition";
  error_messages[ER_SUBPARTITION_NAME - ER_ERROR_FIRST] = "Subpartition";
  error_messages[ER_TEMPORARY_NAME - ER_ERROR_FIRST]    = "Temporary";
  error_messages[ER_RENAMED_NAME - ER_ERROR_FIRST]      = "Renamed";

  my_default_lc_messages->errmsgs->errmsgs = error_messages;

  return 0;
}

void test_1(const char *in, const char *exp, enum_explain_filename_mode mode)
{
  char out[BUFLEN];

  uint len1 = explain_filename(0, in, out, BUFLEN, mode);

  /* expected output and actual output must be same */
  bool pass = (strcmp(exp, out) == 0);

  /* length returned by explain_filename is fine */
  bool length = (len1 == strlen(exp));

  ok( (pass && length) , "(%d): %s => %s\n", mode, in, out);
}

int main()
{
  setup();
  plan(22);

  test_1("test/t1.ibd",
         "Database \"test\", Table \"t1.ibd\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1.ibd",
         "\"test\".\"t1.ibd\"",
         EXPLAIN_PARTITIONS_VERBOSE);

  test_1("test/t1.ibd",
         "\"test\".\"t1.ibd\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#TMP#",
         "Database \"test\", Table \"t1#TMP#\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/#sql-2882.ibd",
         "Database \"test\", Table \"#sql-2882.ibd\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1#REN#",
         "Database \"test\", Table \"t1#REN#\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1@0023REN@0023",
         "Database \"test\", Table \"t1#REN#\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1#p#p1",
         "Database \"test\", Table \"t1\", Partition \"p1\"",
         EXPLAIN_ALL_VERBOSE);

  test_1("test/t1#P#p1",
         "\"test\".\"t1\" /* Partition \"p1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#P#p1@00231",
         "\"test\".\"t1\" /* Partition \"p1#1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#P#p1#SP#sp1",
         "\"test\".\"t1\" /* Partition \"p1\", Subpartition \"sp1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#p1#SP#sp1",
         "\"test\".\"t1#p1#SP#sp1\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#p#p1@00232#SP#sp1@00231#REN#",
         "\"test\".\"t1\" /* Renamed Partition \"p1#2\", Subpartition \"sp1#1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t1#p#p1#SP#sp1#TMP#",
         "\"test\".\"t1\" /* Temporary Partition \"p1\", Subpartition \"sp1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/#sql-t1#P#p1#SP#sp1#TMP#",
         "\"test\".\"#sql-t1#P#p1#SP#sp1#TMP#\" /* Temporary Partition \"p1\", Subpartition \"sp1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/#sql-t1#P#p1#SP#sp1",
         "\"test\".\"#sql-t1#P#p1#SP#sp1\" /* Partition \"p1\", Subpartition \"sp1\" */",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/#sqlx-33",
         "\"test\".\"#sqlx-33\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/#mysql50#t",
         "\"test\".\"#mysql50#t\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("#mysql50#t",
         "\"#mysql50#t\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("@0023t",
         "\"#t\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  test_1("test/t@0023",
         "\"test\".\"t#\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  /*
    If a character not allowed in my_charset_filename is encountered,
    then it will not be converted to system_charset_info!
  */
  test_1("test/t@0023#",
         "\"test\".\"t@0023#\"",
         EXPLAIN_PARTITIONS_AS_COMMENT);

  return exit_status();
}

<|endoftext|>


<commit_before>//===- Local.cpp - Unit tests for Local -----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Utils/Local.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"

using namespace llvm;

TEST(Local, RecursivelyDeleteDeadPHINodes) {
  LLVMContext C;

  IRBuilder<> builder(C);

  // Make blocks
  BasicBlock *bb0 = BasicBlock::Create(C);
  BasicBlock *bb1 = BasicBlock::Create(C);

  builder.SetInsertPoint(bb0);
  PHINode    *phi = builder.CreatePHI(Type::getInt32Ty(C), 2);
  BranchInst *br0 = builder.CreateCondBr(builder.getTrue(), bb0, bb1);

  builder.SetInsertPoint(bb1);
  BranchInst *br1 = builder.CreateBr(bb0);

  phi->addIncoming(phi, bb0);
  phi->addIncoming(phi, bb1);

  // The PHI will be removed
  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  // Make sure the blocks only contain the branches
  EXPECT_EQ(&bb0->front(), br0);
  EXPECT_EQ(&bb1->front(), br1);

  builder.SetInsertPoint(bb0);
  phi = builder.CreatePHI(Type::getInt32Ty(C), 0);

  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  builder.SetInsertPoint(bb0);
  phi = builder.CreatePHI(Type::getInt32Ty(C), 0);
  builder.CreateAdd(phi, phi);

  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  bb0->dropAllReferences();
  bb1->dropAllReferences();
  delete bb0;
  delete bb1;
}

TEST(Local, RemoveDuplicatePHINodes) {
  LLVMContext C;
  IRBuilder<> B(C);

  std::unique_ptr<Function> F(
      Function::Create(FunctionType::get(B.getVoidTy(), false),
                       GlobalValue::ExternalLinkage, "F"));
  BasicBlock *Entry(BasicBlock::Create(C, "", F.get()));
  BasicBlock *BB(BasicBlock::Create(C, "", F.get()));
  BranchInst::Create(BB, Entry);

  B.SetInsertPoint(BB);

  AssertingVH<PHINode> P1 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P1->addIncoming(B.getInt32(42), Entry);

  PHINode *P2 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P2->addIncoming(B.getInt32(42), Entry);

  AssertingVH<PHINode> P3 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P3->addIncoming(B.getInt32(42), Entry);
  P3->addIncoming(B.getInt32(23), BB);

  PHINode *P4 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P4->addIncoming(B.getInt32(42), Entry);
  P4->addIncoming(B.getInt32(23), BB);

  P1->addIncoming(P3, BB);
  P2->addIncoming(P4, BB);
  BranchInst::Create(BB, BB);

  // Verify that we can eliminate PHIs that become duplicates after chaning PHIs
  // downstream.
  EXPECT_TRUE(EliminateDuplicatePHINodes(BB));
  EXPECT_EQ(3U, BB->size());
}

std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
  SMDiagnostic Err;
  std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
  if (!Mod)
    Err.print("UtilsTests", errs());
  return Mod;
}

TEST(Local, ReplaceDbgDeclare) {
  LLVMContext C;

  // Original C source to get debug info for a local variable:
  // void f() { int x; }
  std::unique_ptr<Module> M = parseIR(
      C,
      "define void @f() !dbg !8 {\n"
      "entry:\n"
      "  %x = alloca i32, align 4\n"
      "  call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
      "!DIExpression()), !dbg !13\n"
      "  call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
      "!DIExpression()), !dbg !13\n"
      "  ret void, !dbg !14\n"
      "}\n"
      "declare void @llvm.dbg.declare(metadata, metadata, metadata)\n"
      "!llvm.dbg.cu = !{!0}\n"
      "!llvm.module.flags = !{!3, !4}\n"
      "!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "
      "\"clang version 6.0.0 \", isOptimized: false, runtimeVersion: 0, "
      "emissionKind: FullDebug, enums: !2)\n"
      "!1 = !DIFile(filename: \"t2.c\", directory: \"foo\")\n"
      "!2 = !{}\n"
      "!3 = !{i32 2, !\"Dwarf Version\", i32 4}\n"
      "!4 = !{i32 2, !\"Debug Info Version\", i32 3}\n"
      "!8 = distinct !DISubprogram(name: \"f\", scope: !1, file: !1, line: 1, "
      "type: !9, isLocal: false, isDefinition: true, scopeLine: 1, "
      "isOptimized: false, unit: !0, variables: !2)\n"
      "!9 = !DISubroutineType(types: !10)\n"
      "!10 = !{null}\n"
      "!11 = !DILocalVariable(name: \"x\", scope: !8, file: !1, line: 2, type: "
      "!12)\n"
      "!12 = !DIBasicType(name: \"int\", size: 32, encoding: DW_ATE_signed)\n"
      "!13 = !DILocation(line: 2, column: 7, scope: !8)\n"
      "!14 = !DILocation(line: 3, column: 1, scope: !8)\n");
  auto *GV = M->getNamedValue("f");
  ASSERT_TRUE(GV);
  auto *F = dyn_cast<Function>(GV);
  ASSERT_TRUE(F);
  Instruction *Inst = &F->front().front();
  auto *AI = dyn_cast<AllocaInst>(Inst);
  ASSERT_TRUE(AI);
  Inst = Inst->getNextNode()->getNextNode();
  ASSERT_TRUE(Inst);
  auto *DII = dyn_cast<DbgDeclareInst>(Inst);
  ASSERT_TRUE(DII);
  Value *NewBase = Constant::getNullValue(Type::getInt32PtrTy(C));
  DIBuilder DIB(*M);
  replaceDbgDeclare(AI, NewBase, DII, DIB, DIExpression::NoDeref, 0,
                    DIExpression::NoDeref);

  // There should be exactly two dbg.declares.
  int Declares = 0;
  for (const Instruction &I : F->front())
    if (isa<DbgDeclareInst>(I))
      Declares++;
  EXPECT_EQ(2, Declares);
}

/// Build the dominator tree for the function and run the Test.
static void runWithDomTree(
    Module &M, StringRef FuncName,
    function_ref<void(Function &F, DominatorTree *DT)> Test) {
  auto *F = M.getFunction(FuncName);
  ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
  // Compute the dominator tree for the function.
  DominatorTree DT(*F);
  Test(*F, &DT);
}

TEST(Local, MergeBasicBlockIntoOnlyPred) {
  LLVMContext C;

  std::unique_ptr<Module> M = parseIR(
      C,
      "define i32 @f(i8* %str) {\n"
      "entry:\n"
      "  br label %bb2.i\n"
      "bb2.i:                                            ; preds = %bb4.i, %entry\n"
      "  br i1 false, label %bb4.i, label %base2flt.exit204\n"
      "bb4.i:                                            ; preds = %bb2.i\n"
      "  br i1 false, label %base2flt.exit204, label %bb2.i\n"
      "bb10.i196.bb7.i197_crit_edge:                     ; No predecessors!\n"
      "  br label %bb7.i197\n"
      "bb7.i197:                                         ; preds = %bb10.i196.bb7.i197_crit_edge\n"
      "  %.reg2mem.0 = phi i32 [ %.reg2mem.0, %bb10.i196.bb7.i197_crit_edge ]\n"
      "  br i1 undef, label %base2flt.exit204, label %base2flt.exit204\n"
      "base2flt.exit204:                                 ; preds = %bb7.i197, %bb7.i197, %bb2.i, %bb4.i\n"
      "  ret i32 0\n"
      "}\n");
  runWithDomTree(
      *M, "f", [&](Function &F, DominatorTree *DT) {
        for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
          BasicBlock *BB = &*I++;
          BasicBlock *SinglePred = BB->getSinglePredecessor();
          if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) continue;
          BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());
          if (Term && !Term->isConditional())
            MergeBasicBlockIntoOnlyPred(BB, DT);
        }
        EXPECT_TRUE(DT->verify());
      });
}
<commit_msg>[unittests] Make some parseIR calls more readable, NFC<commit_after>//===- Local.cpp - Unit tests for Local -----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Utils/Local.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"

using namespace llvm;

TEST(Local, RecursivelyDeleteDeadPHINodes) {
  LLVMContext C;

  IRBuilder<> builder(C);

  // Make blocks
  BasicBlock *bb0 = BasicBlock::Create(C);
  BasicBlock *bb1 = BasicBlock::Create(C);

  builder.SetInsertPoint(bb0);
  PHINode    *phi = builder.CreatePHI(Type::getInt32Ty(C), 2);
  BranchInst *br0 = builder.CreateCondBr(builder.getTrue(), bb0, bb1);

  builder.SetInsertPoint(bb1);
  BranchInst *br1 = builder.CreateBr(bb0);

  phi->addIncoming(phi, bb0);
  phi->addIncoming(phi, bb1);

  // The PHI will be removed
  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  // Make sure the blocks only contain the branches
  EXPECT_EQ(&bb0->front(), br0);
  EXPECT_EQ(&bb1->front(), br1);

  builder.SetInsertPoint(bb0);
  phi = builder.CreatePHI(Type::getInt32Ty(C), 0);

  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  builder.SetInsertPoint(bb0);
  phi = builder.CreatePHI(Type::getInt32Ty(C), 0);
  builder.CreateAdd(phi, phi);

  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  bb0->dropAllReferences();
  bb1->dropAllReferences();
  delete bb0;
  delete bb1;
}

TEST(Local, RemoveDuplicatePHINodes) {
  LLVMContext C;
  IRBuilder<> B(C);

  std::unique_ptr<Function> F(
      Function::Create(FunctionType::get(B.getVoidTy(), false),
                       GlobalValue::ExternalLinkage, "F"));
  BasicBlock *Entry(BasicBlock::Create(C, "", F.get()));
  BasicBlock *BB(BasicBlock::Create(C, "", F.get()));
  BranchInst::Create(BB, Entry);

  B.SetInsertPoint(BB);

  AssertingVH<PHINode> P1 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P1->addIncoming(B.getInt32(42), Entry);

  PHINode *P2 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P2->addIncoming(B.getInt32(42), Entry);

  AssertingVH<PHINode> P3 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P3->addIncoming(B.getInt32(42), Entry);
  P3->addIncoming(B.getInt32(23), BB);

  PHINode *P4 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P4->addIncoming(B.getInt32(42), Entry);
  P4->addIncoming(B.getInt32(23), BB);

  P1->addIncoming(P3, BB);
  P2->addIncoming(P4, BB);
  BranchInst::Create(BB, BB);

  // Verify that we can eliminate PHIs that become duplicates after chaning PHIs
  // downstream.
  EXPECT_TRUE(EliminateDuplicatePHINodes(BB));
  EXPECT_EQ(3U, BB->size());
}

std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
  SMDiagnostic Err;
  std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
  if (!Mod)
    Err.print("UtilsTests", errs());
  return Mod;
}

TEST(Local, ReplaceDbgDeclare) {
  LLVMContext C;

  // Original C source to get debug info for a local variable:
  // void f() { int x; }
  std::unique_ptr<Module> M = parseIR(C,
                                      R"(
      define void @f() !dbg !8 {
      entry:
        %x = alloca i32, align 4
        call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata !DIExpression()), !dbg !13
        call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata !DIExpression()), !dbg !13
        ret void, !dbg !14
      }
      declare void @llvm.dbg.declare(metadata, metadata, metadata)
      !llvm.dbg.cu = !{!0}
      !llvm.module.flags = !{!3, !4}
      !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
      !1 = !DIFile(filename: "t2.c", directory: "foo")
      !2 = !{}
      !3 = !{i32 2, !"Dwarf Version", i32 4}
      !4 = !{i32 2, !"Debug Info Version", i32 3}
      !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, variables: !2)
      !9 = !DISubroutineType(types: !10)
      !10 = !{null}
      !11 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !12)
      !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
      !13 = !DILocation(line: 2, column: 7, scope: !8)
      !14 = !DILocation(line: 3, column: 1, scope: !8)
      )");
  auto *GV = M->getNamedValue("f");
  ASSERT_TRUE(GV);
  auto *F = dyn_cast<Function>(GV);
  ASSERT_TRUE(F);
  Instruction *Inst = &F->front().front();
  auto *AI = dyn_cast<AllocaInst>(Inst);
  ASSERT_TRUE(AI);
  Inst = Inst->getNextNode()->getNextNode();
  ASSERT_TRUE(Inst);
  auto *DII = dyn_cast<DbgDeclareInst>(Inst);
  ASSERT_TRUE(DII);
  Value *NewBase = Constant::getNullValue(Type::getInt32PtrTy(C));
  DIBuilder DIB(*M);
  replaceDbgDeclare(AI, NewBase, DII, DIB, DIExpression::NoDeref, 0,
                    DIExpression::NoDeref);

  // There should be exactly two dbg.declares.
  int Declares = 0;
  for (const Instruction &I : F->front())
    if (isa<DbgDeclareInst>(I))
      Declares++;
  EXPECT_EQ(2, Declares);
}

/// Build the dominator tree for the function and run the Test.
static void runWithDomTree(
    Module &M, StringRef FuncName,
    function_ref<void(Function &F, DominatorTree *DT)> Test) {
  auto *F = M.getFunction(FuncName);
  ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
  // Compute the dominator tree for the function.
  DominatorTree DT(*F);
  Test(*F, &DT);
}

TEST(Local, MergeBasicBlockIntoOnlyPred) {
  LLVMContext C;

  std::unique_ptr<Module> M = parseIR(C,
                                      R"(
      define i32 @f(i8* %str) {
      entry:
        br label %bb2.i
      bb2.i:                                            ; preds = %bb4.i, %entry
        br i1 false, label %bb4.i, label %base2flt.exit204
      bb4.i:                                            ; preds = %bb2.i
        br i1 false, label %base2flt.exit204, label %bb2.i
      bb10.i196.bb7.i197_crit_edge:                     ; No predecessors!
        br label %bb7.i197
      bb7.i197:                                         ; preds = %bb10.i196.bb7.i197_crit_edge
        %.reg2mem.0 = phi i32 [ %.reg2mem.0, %bb10.i196.bb7.i197_crit_edge ]
        br i1 undef, label %base2flt.exit204, label %base2flt.exit204
      base2flt.exit204:                                 ; preds = %bb7.i197, %bb7.i197, %bb2.i, %bb4.i
        ret i32 0
      }
      )");
  runWithDomTree(
      *M, "f", [&](Function &F, DominatorTree *DT) {
        for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
          BasicBlock *BB = &*I++;
          BasicBlock *SinglePred = BB->getSinglePredecessor();
          if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) continue;
          BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());
          if (Term && !Term->isConditional())
            MergeBasicBlockIntoOnlyPred(BB, DT);
        }
        EXPECT_TRUE(DT->verify());
      });
}
<|endoftext|>


<commit_before>#include "Vertex.hpp"
#include "GameManager.hpp"
#include "simple_hero.hpp"
#include "stdio.h"

int main( void ) {
	GraphMap* map = new GraphMap( fopen( "maps/basic.txt", "r" ) );

	Simple_Hero hero( 1 );

	hero.make_graph( map );

	delete( map );
	return 0;
}
<commit_msg>Vertex is actually vertex<commit_after>#include "vertex.hpp"
#include "GameManager.hpp"
#include "simple_hero.hpp"
#include "stdio.h"

int main( void ) {
	GraphMap* map = new GraphMap( fopen( "maps/basic.txt", "r" ) );

	Simple_Hero hero( 1 );

	hero.make_graph( map );

	delete( map );
	return 0;
}
<|endoftext|>