<commit_before>#include "RobotService.h"
#include <boost/thread.hpp>

namespace {
  /**
   * Callback invoked when the async connect operation completes.
   */
  void connect_handler(boost::system::error_code const& error) {
    if (!error) {
      std::cerr << "AsyncRobotService: Connected to the robot." << std::endl;
    } else {
      std::cerr << "AsyncRobotService: Failed to connect to the robot" << std::endl;
    }
  }

  /**
   * A simple function that is used to spin up the io service event loop in a
   * dedicated thread.
   * Makes sure that the loop does not end when the service does not have any
   * work to do (temporarily).
   */
  void service_thread(boost::asio::io_service* io_service) {
    // Prevent the IO service from running out of work (and exitting when no
    // async operations are queued).
    boost::asio::io_service::work work(*io_service);
    io_service->run();
    std::cout << "AsyncRobotService: Exiting service thread..." << std::endl;
  }

  /**
   * A callback for write operations.
   */
  void write_handler(boost::system::error_code const& error,
               std::size_t sent) {
    if (!error) {
      std::cerr << "AsyncRobotService: Send complete. "
                << "Sent " << sent << " bytes." << std::endl;
    } else {
      std::cerr << "AsyncRobotService: Error sending message." << std::endl;
    }
  }
}

VisionMessage VisionMessage::DeleteMessage(int model_id) {
  std::cout << "Constructing with object_id = " << model_id << std::endl;
  VisionMessage msg;
  msg.id = REMOVE_SSV;
  msg.len = sizeof params;
  memset(msg.params, 0, sizeof msg.params);
  // 0 - unused, no point setting the type
  msg.params[1] = model_id;
  // 2 - unused -- since the entire model is getting removed...
  // 3 - unused, no point setting the radius
  msg.params[4] = VisionMessage::DEL_WHOLE_SEGMENT_FLAG;
  // The rest of the parameters are also irrelevant.
  std::cout << "Constructed " << msg << std::endl;
  return msg;
}

VisionMessage VisionMessage::DeletePartMessage(int model_id, int part_id) {
  std::cout << "Constructing with object_id = " << part_id << std::endl;
  VisionMessage msg;
  msg.id = REMOVE_SSV;
  msg.len = sizeof params;
  memset(msg.params, 0, sizeof msg.params);
  // 0 - unused, no point setting the type
  msg.params[1] = model_id;
  msg.params[2] = part_id;
  // 3 - unused, no point setting the radius
  msg.params[4] = VisionMessage::DEL_ONLY_PART_FLAG;
  // The rest of the parameters are also irrelevant.
  std::cout << "Constructed " << msg << std::endl;
  return msg;
}

VisionMessage VisionMessage::SetMessage(
    int type_id, int model_id, int part_id, double radius, std::vector<double> const& coefs) {
  VisionMessage msg;
  msg.id = SET_SSV;
  memset(msg.params, 0, sizeof msg.params);
  msg.params[0] = type_id;
  msg.params[1] = model_id;
  msg.params[2] = part_id;
  msg.params[3] = radius;
  // 4 - unused
  // 5 - unused
  for (size_t i = 0; i < coefs.size(); ++i) msg.params[6 + i] = coefs[i];

  return msg;
}

VisionMessage VisionMessage::ModifyMessage(
    int type_id, int model_id, int part_id, double radius, std::vector<double> const& coefs) {
  VisionMessage msg;
  msg.id = MODIFY_SSV;
  memset(msg.params, 0, sizeof msg.params);
  msg.params[0] = type_id;
  msg.params[1] = model_id;
  msg.params[2] = part_id;
  msg.params[3] = radius;
  // 4 - unused
  // 5 - unused
  for (size_t i = 0; i < coefs.size(); ++i) msg.params[6 + i] = coefs[i];

  return msg;
}

std::ostream& operator<<(std::ostream& out, VisionMessage const& msg) {
  out << "[" << msg.id << " | " << msg.len << " | ";
  for (size_t i = 0; i < 15; ++i) out << msg.params[i] << ", ";
  out << "]";

  return out;
}

void AsyncRobotService::start() {
  // Start it up...
  boost::asio::ip::tcp::endpoint endpoint(
    boost::asio::ip::address::from_string(remote_), port_);
  std::cerr << "AsyncRobotService: Initiating a connection asynchronously..."
            << std::endl;
  socket_.async_connect(endpoint, connect_handler);
  // Start the service thread in the background...
  boost::thread(boost::bind(service_thread, &io_service_));
}

void AsyncRobotService::inner_send(VisionMessage const& next_message) {
  char const* buf = (char const*)&next_message;
  std::cerr << "AsyncRobotService: Sending a queued message: "
            << "msg == " << next_message
            << std::endl;
  // Synchronously send the message, i.e. block until the send is complete.
  socket_.send(
      boost::asio::buffer(buf, sizeof(VisionMessage)));
  // After each sent message, we want to wait a pre-defined amount of time
  // before sending the next one.
  // This is because we do not want to overwhelm the robot with a large
  // number of messages all sent in the same time.
  boost::this_thread::sleep(message_timeout_);
}

void AsyncRobotService::sendMessage(VisionMessage const& msg) {
  // Just queue another message to be sent by the io_service thread.
  // Since `inner_send` makes sure to wait after it's finished sending
  // each message (i.e. the io_service thread is blocked), the queued
  // messages will all be sent with a preset time delay between subsequent
  // messages.
  io_service_.post(boost::bind(&AsyncRobotService::inner_send, this, msg));
}
<commit_msg>AsyncRobotService: Handle failed socket writes<commit_after>#include "RobotService.h"
#include <boost/thread.hpp>

namespace {
  /**
   * Callback invoked when the async connect operation completes.
   */
  void connect_handler(boost::system::error_code const& error) {
    if (!error) {
      std::cerr << "AsyncRobotService: Connected to the robot." << std::endl;
    } else {
      std::cerr << "AsyncRobotService: Failed to connect to the robot" << std::endl;
    }
  }

  /**
   * A simple function that is used to spin up the io service event loop in a
   * dedicated thread.
   * Makes sure that the loop does not end when the service does not have any
   * work to do (temporarily).
   */
  void service_thread(boost::asio::io_service* io_service) {
    // Prevent the IO service from running out of work (and exitting when no
    // async operations are queued).
    boost::asio::io_service::work work(*io_service);
    io_service->run();
    std::cout << "AsyncRobotService: Exiting service thread..." << std::endl;
  }

  /**
   * A callback for write operations.
   */
  void write_handler(boost::system::error_code const& error,
               std::size_t sent) {
    if (!error) {
      std::cerr << "AsyncRobotService: Send complete. "
                << "Sent " << sent << " bytes." << std::endl;
    } else {
      std::cerr << "AsyncRobotService: Error sending message." << std::endl;
    }
  }
}

VisionMessage VisionMessage::DeleteMessage(int model_id) {
  std::cout << "Constructing with object_id = " << model_id << std::endl;
  VisionMessage msg;
  msg.id = REMOVE_SSV;
  msg.len = sizeof params;
  memset(msg.params, 0, sizeof msg.params);
  // 0 - unused, no point setting the type
  msg.params[1] = model_id;
  // 2 - unused -- since the entire model is getting removed...
  // 3 - unused, no point setting the radius
  msg.params[4] = VisionMessage::DEL_WHOLE_SEGMENT_FLAG;
  // The rest of the parameters are also irrelevant.
  std::cout << "Constructed " << msg << std::endl;
  return msg;
}

VisionMessage VisionMessage::DeletePartMessage(int model_id, int part_id) {
  std::cout << "Constructing with object_id = " << part_id << std::endl;
  VisionMessage msg;
  msg.id = REMOVE_SSV;
  msg.len = sizeof params;
  memset(msg.params, 0, sizeof msg.params);
  // 0 - unused, no point setting the type
  msg.params[1] = model_id;
  msg.params[2] = part_id;
  // 3 - unused, no point setting the radius
  msg.params[4] = VisionMessage::DEL_ONLY_PART_FLAG;
  // The rest of the parameters are also irrelevant.
  std::cout << "Constructed " << msg << std::endl;
  return msg;
}

VisionMessage VisionMessage::SetMessage(
    int type_id, int model_id, int part_id, double radius, std::vector<double> const& coefs) {
  VisionMessage msg;
  msg.id = SET_SSV;
  memset(msg.params, 0, sizeof msg.params);
  msg.params[0] = type_id;
  msg.params[1] = model_id;
  msg.params[2] = part_id;
  msg.params[3] = radius;
  // 4 - unused
  // 5 - unused
  for (size_t i = 0; i < coefs.size(); ++i) msg.params[6 + i] = coefs[i];

  return msg;
}

VisionMessage VisionMessage::ModifyMessage(
    int type_id, int model_id, int part_id, double radius, std::vector<double> const& coefs) {
  VisionMessage msg;
  msg.id = MODIFY_SSV;
  memset(msg.params, 0, sizeof msg.params);
  msg.params[0] = type_id;
  msg.params[1] = model_id;
  msg.params[2] = part_id;
  msg.params[3] = radius;
  // 4 - unused
  // 5 - unused
  for (size_t i = 0; i < coefs.size(); ++i) msg.params[6 + i] = coefs[i];

  return msg;
}

std::ostream& operator<<(std::ostream& out, VisionMessage const& msg) {
  out << "[" << msg.id << " | " << msg.len << " | ";
  for (size_t i = 0; i < 15; ++i) out << msg.params[i] << ", ";
  out << "]";

  return out;
}

void AsyncRobotService::start() {
  // Start it up...
  boost::asio::ip::tcp::endpoint endpoint(
    boost::asio::ip::address::from_string(remote_), port_);
  std::cerr << "AsyncRobotService: Initiating a connection asynchronously..."
            << std::endl;
  socket_.async_connect(endpoint, connect_handler);
  // Start the service thread in the background...
  boost::thread(boost::bind(service_thread, &io_service_));
}

void AsyncRobotService::inner_send(VisionMessage const& next_message) {
  char const* buf = (char const*)&next_message;
  std::cerr << "AsyncRobotService: Sending a queued message: "
            << "msg == " << next_message
            << std::endl;
  // Synchronously send the message, i.e. block until the send is complete.
  try {
    socket_.send(
        boost::asio::buffer(buf, sizeof(VisionMessage)));
  } catch (...) {
    std::cerr << "AsyncRobotService: Error sending message." << std::endl;
  }
  // After each sent message, we want to wait a pre-defined amount of time
  // before sending the next one.
  // This is because we do not want to overwhelm the robot with a large
  // number of messages all sent in the same time.
  boost::this_thread::sleep(message_timeout_);
}

void AsyncRobotService::sendMessage(VisionMessage const& msg) {
  // Just queue another message to be sent by the io_service thread.
  // Since `inner_send` makes sure to wait after it's finished sending
  // each message (i.e. the io_service thread is blocked), the queued
  // messages will all be sent with a preset time delay between subsequent
  // messages.
  io_service_.post(boost::bind(&AsyncRobotService::inner_send, this, msg));
}
<|endoftext|>


<commit_before>#include "direntry.hpp"
#include <algorithm>
#include <sstream>
#include <vector>
#

using std::find_if;
using std::istringstream;
using std::make_shared;
using std::shared_ptr;
using std::string;
using std::vector;
using std::weak_ptr;

DirEntry::DirEntry() {}

shared_ptr<DirEntry> DirEntry::mk_DirEntry(const string name,
                                           const shared_ptr<DirEntry> parent,
                                           const shared_ptr<Inode> &inode) {
  auto sp = make_shared<DirEntry>(DirEntry());
  if (parent == nullptr) {
    sp->parent = sp;
  } else {
    sp->parent = parent;
  }
  sp->self = sp;
  sp->name = name;
  sp->inode = inode;
  return sp;
}

shared_ptr<DirEntry> DirEntry::find_child(const string name) const {
  // handle . and ..
  if (name == "..") {
    return parent.lock();
  } else if (name == ".") {
    return self.lock();
  }

  // search through contents and return ptr if found, otherwise nullptr
  auto named = [&] (const shared_ptr<DirEntry> de) {return de->name == name;};
  auto it = find_if(begin(contents), end(contents), named);
  if (it == end(contents)) {
    return nullptr;
  }

  return *it;
}

shared_ptr<DirEntry> DirEntry::add_dir(const string name) {
  auto new_dir = mk_DirEntry(name, self.lock());
  contents.push_back(new_dir);
  return new_dir;
}

shared_ptr<DirEntry> DirEntry::add_file(const string name) {
  auto new_file = mk_DirEntry(name, self.lock(), make_shared<Inode>());
  contents.push_back(new_file);
  return new_file;
}
<commit_msg>forgot to set type when making DirEntry nodes<commit_after>#include "direntry.hpp"
#include <algorithm>
#include <sstream>
#include <vector>
#

using std::find_if;
using std::istringstream;
using std::make_shared;
using std::shared_ptr;
using std::string;
using std::vector;
using std::weak_ptr;

DirEntry::DirEntry() {}

shared_ptr<DirEntry> DirEntry::mk_DirEntry(const string name,
                                           const shared_ptr<DirEntry> parent,
                                           const shared_ptr<Inode> &inode) {
  auto sp = make_shared<DirEntry>(DirEntry());
  if (parent == nullptr) {
    sp->parent = sp;
  } else {
    sp->parent = parent;
  }
  sp->self = sp;
  sp->name = name;
  sp->inode = inode;
  return sp;
}

shared_ptr<DirEntry> DirEntry::find_child(const string name) const {
  // handle . and ..
  if (name == "..") {
    return parent.lock();
  } else if (name == ".") {
    return self.lock();
  }

  // search through contents and return ptr if found, otherwise nullptr
  auto named = [&] (const shared_ptr<DirEntry> de) {return de->name == name;};
  auto it = find_if(begin(contents), end(contents), named);
  if (it == end(contents)) {
    return nullptr;
  }

  return *it;
}

shared_ptr<DirEntry> DirEntry::add_dir(const string name) {
  auto new_dir = mk_DirEntry(name, self.lock());
  new_dir->type = dir;
  contents.push_back(new_dir);
  return new_dir;
}

shared_ptr<DirEntry> DirEntry::add_file(const string name) {
  auto new_file = mk_DirEntry(name, self.lock(), make_shared<Inode>());
  new_file->type = file;
  contents.push_back(new_file);
  return new_file;
}
<|endoftext|>


<commit_before>#include "GameProcess.h"
#include "Object.h"
#include "Engine.h"
#include "World.h"
using namespace MathLib;

CGameProcess::CGameProcess(void)
{

}

CGameProcess::~CGameProcess(void)
{

}<commit_msg>Signed-off-by: mrlitong <litongtongxue@gmail.com><commit_after>#include "GameProcess.h"
#include "Object.h"
#include "Engine.h"
#include "World.h"
using namespace MathLib;

CGameProcess::CGameProcess(void)
{

}

CGameProcess::~CGameProcess(void)
{

}
int CGameProcess::Init()
{
	g_Engine.pFileSystem->CacheFilesFormExt("char");
	g_Engine.pFileSystem->CacheFilesFormExt("node");

}<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/perv/p10_hang_pulse_mc_setup_tables.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/*
 * We're making all these tables "static const" since they're being used
 * in one place only each, and we trust the compiler to leave them out
 * of a module if they're not used.
 */

#include <multicast_group_defs.H>

static const hang_pulse_t SETUP_HANG_COUNTERS_PERV[] =
{
    {0, 16, 0},
    {1, 4, 0},
    {2, 18, 0},
    {3, 1, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_PULSE_FREQ[] =
{
    {0, 1, 0},
    {1, 31, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_N0[] =
{
    {0, 16, 0},
    {1, 24, 0},
    {2, 34, 0},
    {3, 15, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_N1[] =
{
    {0, 16, 0},
    {1, 23, 0},
    {2, 15, 0},
    {3, 19, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_PCI[] =
{
    {0, 16, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_MC[] =
{
    {0, 16, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_IOHS[] =
{
    {0, 16, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_PAU[] =
{
    {0, 16, 0},
    {1, 4, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_EQ[] =
{
    {0, 16, 0},
    {1, 23, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const mc_setup_t ISTEP3_MC_GROUPS[] =
{
    { fapi2::MCGROUP_GOOD,       MC_GROUP_0, HONOR_PGOOD,          0, 0x7FFFFFFFFFFFFFFF },
    { fapi2::MCGROUP_GOOD_NO_TP, MC_GROUP_1, HONOR_PGOOD_FORCE_EQ, 0, 0x3FFFFFFFFFFFFFFF },
    { fapi2::MCGROUP_GOOD_MC,    MC_GROUP_2, HONOR_PGOOD,          0, 0x000F000000000000 },
    { fapi2::MCGROUP_GOOD_IOHS,  MC_GROUP_3, HONOR_PGOOD,          0, 0x000000FF00000000 },
    { fapi2::MCGROUP_GOOD_PAU,   MC_GROUP_4, HONOR_PGOOD,          0, 0x0000F00000000000 },
    { fapi2::MCGROUP_GOOD_PCI,   MC_GROUP_5, HONOR_PGOOD,          0, 0x00C0000000000000 },
    { fapi2::MCGROUP_ALL_EQ,     MC_GROUP_6, HONOR_PGOOD,          1, 0x00000000FF000000 },
};

static const mc_setup_t ISTEP4_MC_GROUPS[] =
{
    { fapi2::MCGROUP_GOOD,       MC_GROUP_0, HONOR_PGOOD,      0, 0x7FFFFFFFFFFFFFFF },
    { fapi2::MCGROUP_GOOD_NO_TP, MC_GROUP_1, HONOR_PGOOD,      0, 0x3FFFFFFFFFFFFFFF },
    { fapi2::MCGROUP_GOOD_MC,    MC_GROUP_2, HONOR_PGOOD,      0, 0x000F000000000000 },
    { fapi2::MCGROUP_GOOD_IOHS,  MC_GROUP_3, HONOR_PGOOD,      0, 0x000000FF00000000 },
    { fapi2::MCGROUP_GOOD_PAU,   MC_GROUP_4, HONOR_PGOOD,      0, 0x0000F00000000000 },
    { fapi2::MCGROUP_GOOD_PCI,   MC_GROUP_5, HONOR_PGOOD,      0, 0x00C0000000000000 },
    { fapi2::MCGROUP_GOOD_EQ,    MC_GROUP_6, HONOR_CORE_PGOOD, 1, 0x00000000FF000000 },
};
<commit_msg>IPL HWP updates<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/perv/p10_hang_pulse_mc_setup_tables.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2020                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

/*
 * We're making all these tables "static const" since they're being used
 * in one place only each, and we trust the compiler to leave them out
 * of a module if they're not used.
 */

#include <multicast_group_defs.H>

static const hang_pulse_t SETUP_HANG_COUNTERS_PERV[] =
{
    {0, 16, 0},
    {1, 4, 0},
    {2, 18, 0},
    {3, 1, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_PULSE_FREQ[] =
{
    {0, 1, 0},
    {1, 31, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_N0[] =
{
    {0, 16, 0},
    {1, 24, 0},
    {2, 34, 0},
    {3, 15, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_N1[] =
{
    {0, 16, 0},
    {1, 23, 0},
    {2, 15, 0},
    {3, 19, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_PCI[] =
{
    {0, 16, 0},
    {1, 44, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_MC[] =
{
    {0, 16, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_IOHS[] =
{
    {0, 16, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_PAU[] =
{
    {0, 16, 0},
    {1, 4, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const hang_pulse_t SETUP_HANG_COUNTERS_EQ[] =
{
    {0, 16, 0},
    {1, 23, 0},
    {5, 6, 0},
    {6, 8, 0, 1}
};

static const mc_setup_t ISTEP3_MC_GROUPS[] =
{
    { fapi2::MCGROUP_GOOD,       MC_GROUP_0, HONOR_PGOOD,          0, 0x7FFFFFFFFFFFFFFF },
    { fapi2::MCGROUP_GOOD_NO_TP, MC_GROUP_1, HONOR_PGOOD_FORCE_EQ, 0, 0x3FFFFFFFFFFFFFFF },
    { fapi2::MCGROUP_GOOD_MC,    MC_GROUP_2, HONOR_PGOOD,          0, 0x000F000000000000 },
    { fapi2::MCGROUP_GOOD_IOHS,  MC_GROUP_3, HONOR_PGOOD,          0, 0x000000FF00000000 },
    { fapi2::MCGROUP_GOOD_PAU,   MC_GROUP_4, HONOR_PGOOD,          0, 0x0000F00000000000 },
    { fapi2::MCGROUP_GOOD_PCI,   MC_GROUP_5, HONOR_PGOOD,          0, 0x00C0000000000000 },
    { fapi2::MCGROUP_ALL_EQ,     MC_GROUP_6, HONOR_PGOOD,          1, 0x00000000FF000000 },
};

static const mc_setup_t ISTEP4_MC_GROUPS[] =
{
    { fapi2::MCGROUP_GOOD,       MC_GROUP_0, HONOR_PGOOD,      0, 0x7FFFFFFFFFFFFFFF },
    { fapi2::MCGROUP_GOOD_NO_TP, MC_GROUP_1, HONOR_PGOOD,      0, 0x3FFFFFFFFFFFFFFF },
    { fapi2::MCGROUP_GOOD_MC,    MC_GROUP_2, HONOR_PGOOD,      0, 0x000F000000000000 },
    { fapi2::MCGROUP_GOOD_IOHS,  MC_GROUP_3, HONOR_PGOOD,      0, 0x000000FF00000000 },
    { fapi2::MCGROUP_GOOD_PAU,   MC_GROUP_4, HONOR_PGOOD,      0, 0x0000F00000000000 },
    { fapi2::MCGROUP_GOOD_PCI,   MC_GROUP_5, HONOR_PGOOD,      0, 0x00C0000000000000 },
    { fapi2::MCGROUP_GOOD_EQ,    MC_GROUP_6, HONOR_CORE_PGOOD, 1, 0x00000000FF000000 },
};
<|endoftext|>


<commit_before>/*
 *  GlobalHistogramBinarizer.cpp
 *  zxing
 *
 *  Created by Ralf Kistner on 16/10/2009.
 *  Copyright 2008 ZXing authors All rights reserved.
 *  Modified by Lukasz Warchol on 02/02/2010.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <zxing/common/GlobalHistogramBinarizer.h>

#include <zxing/common/IllegalArgumentException.h>

namespace zxing {
using namespace std;

const int LUMINANCE_BITS = 5;
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;

GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source) :
  Binarizer(source), cached_matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) {

}

GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {
}

Ref<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row) {
  if (y == cached_row_num_) {
    return cached_row_;
  }

  vector<int> histogram(LUMINANCE_BUCKETS, 0);
  LuminanceSource& source = *getLuminanceSource();
  int width = source.getWidth();
  if (row == NULL || static_cast<int>(row->getSize()) < width) {
    row = new BitArray(width);
  } else {
    row->clear();
  }

  //TODO(flyashi): cache this instead of allocating and deleting per row
  unsigned char* row_pixels = NULL;
  try {
      row_pixels = new unsigned char[width];
      getLuminanceSource()->getRow(y,row_pixels);
      for (int x = 0; x < width; x++) {
          histogram[row_pixels[x] >> LUMINANCE_SHIFT]++;
      }
      int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;

      Ref<BitArray> array_ref(new BitArray(width));
      BitArray& array = *array_ref;

      int left = row_pixels[0];
      int center = row_pixels[1];
      for (int x = 1; x < width - 1; x++) {
          int right = row_pixels[x + 1];
          // A simple -1 4 -1 box filter with a weight of 2.
          int luminance = ((center << 2) - left - right) >> 1;
          if (luminance < blackPoint) {
              array.set(x);
          }
          left = center;
          center = right;
      }

      cached_row_ = array_ref;
      cached_row_num_ = y;
      delete [] row_pixels;
      return array_ref;
  } catch (IllegalArgumentException const& iae) {
      // Cache the fact that this row failed.
      cached_row_ = NULL;
      cached_row_num_ = y;
      delete [] row_pixels;
      throw iae;
  }
}

Ref<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix() {
  if (cached_matrix_ != NULL) {
    return cached_matrix_;
  }

  // Faster than working with the reference
  LuminanceSource& source = *getLuminanceSource();
  int width = source.getWidth();
  int height = source.getHeight();
  vector<int> histogram(LUMINANCE_BUCKETS, 0);

  // Quickly calculates the histogram by sampling four rows from the image.
  // This proved to be more robust on the blackbox tests than sampling a
  // diagonal as we used to do.
  unsigned char* row = new unsigned char[width];
  for (int y = 1; y < 5; y++) {
    int rownum = height * y / 5;
    int right = (width << 2) / 5;
    int sdf;
    getLuminanceSource()->getRow(rownum,row);
    for (int x = width / 5; x < right; x++) {
      histogram[row[x] >> LUMINANCE_SHIFT]++;
      sdf = histogram[row[x] >> LUMINANCE_SHIFT];
    }
  }

  int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;

  Ref<BitMatrix> matrix_ref(new BitMatrix(width, height));
  BitMatrix& matrix = *matrix_ref;
  for (int y = 0; y < height; y++) {
    getLuminanceSource()->getRow(y,row);
    for (int x = 0; x < width; x++) {
      if (row[x] <= blackPoint)
        matrix.set(x, y);
    }
  }

  cached_matrix_ = matrix_ref;

  delete [] row;
  return matrix_ref;
}

int GlobalHistogramBinarizer::estimate(vector<int> &histogram) {
  int numBuckets = histogram.size();
  int maxBucketCount = 0;

  // Find tallest peak in histogram
  int firstPeak = 0;
  int firstPeakSize = 0;
  for (int i = 0; i < numBuckets; i++) {
    if (histogram[i] > firstPeakSize) {
      firstPeak = i;
      firstPeakSize = histogram[i];
    }
    if (histogram[i] > maxBucketCount) {
      maxBucketCount = histogram[i];
    }
  }

  // Find second-tallest peak -- well, another peak that is tall and not
  // so close to the first one
  int secondPeak = 0;
  int secondPeakScore = 0;
  for (int i = 0; i < numBuckets; i++) {
    int distanceToBiggest = i - firstPeak;
    // Encourage more distant second peaks by multiplying by square of distance
    int score = histogram[i] * distanceToBiggest * distanceToBiggest;
    if (score > secondPeakScore) {
      secondPeak = i;
      secondPeakScore = score;
    }
  }

  // Put firstPeak first
  if (firstPeak > secondPeak) {
    int temp = firstPeak;
    firstPeak = secondPeak;
    secondPeak = temp;
  }

  // Kind of arbitrary; if the two peaks are very close, then we figure there is
  // so little dynamic range in the image, that discriminating black and white
  // is too error-prone.
  // Decoding the image/line is either pointless, or may in some cases lead to
  // a false positive for 1D formats, which are relatively lenient.
  // We arbitrarily say "close" is
  // "<= 1/16 of the total histogram buckets apart"
  if (secondPeak - firstPeak <= numBuckets >> 4) {
    throw IllegalArgumentException("Too little dynamic range in luminance");
  }

  // Find a valley between them that is low and closer to the white peak
  int bestValley = secondPeak - 1;
  int bestValleyScore = -1;
  for (int i = secondPeak - 1; i > firstPeak; i--) {
    int fromFirst = i - firstPeak;
    // Favor a "valley" that is not too close to either peak -- especially not
    // the black peak -- and that has a low value of course
    int score = fromFirst * fromFirst * (secondPeak - i) *
      (maxBucketCount - histogram[i]);
    if (score > bestValleyScore) {
      bestValley = i;
      bestValleyScore = score;
    }
  }

  return bestValley;
}

Ref<Binarizer> GlobalHistogramBinarizer::createBinarizer(Ref<LuminanceSource> source) {
  return Ref<Binarizer> (new GlobalHistogramBinarizer(source));
}

} // namespace zxing

<commit_msg>Slight refinement to last change - a cached row which failed should throw an exception, not return NULL.<commit_after>/*
 *  GlobalHistogramBinarizer.cpp
 *  zxing
 *
 *  Created by Ralf Kistner on 16/10/2009.
 *  Copyright 2008 ZXing authors All rights reserved.
 *  Modified by Lukasz Warchol on 02/02/2010.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <zxing/common/GlobalHistogramBinarizer.h>

#include <zxing/common/IllegalArgumentException.h>

namespace zxing {
using namespace std;

const int LUMINANCE_BITS = 5;
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;

GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source) :
  Binarizer(source), cached_matrix_(NULL), cached_row_(NULL), cached_row_num_(-1) {

}

GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {
}

Ref<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row) {
  if (y == cached_row_num_) {
    if (cached_row_ != NULL) {
      return cached_row_;
    } else {
      throw IllegalArgumentException("Too little dynamic range in luminance");
    }
  }

  vector<int> histogram(LUMINANCE_BUCKETS, 0);
  LuminanceSource& source = *getLuminanceSource();
  int width = source.getWidth();
  if (row == NULL || static_cast<int>(row->getSize()) < width) {
    row = new BitArray(width);
  } else {
    row->clear();
  }

  //TODO(flyashi): cache this instead of allocating and deleting per row
  unsigned char* row_pixels = NULL;
  try {
      row_pixels = new unsigned char[width];
      getLuminanceSource()->getRow(y,row_pixels);
      for (int x = 0; x < width; x++) {
          histogram[row_pixels[x] >> LUMINANCE_SHIFT]++;
      }
      int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;

      Ref<BitArray> array_ref(new BitArray(width));
      BitArray& array = *array_ref;

      int left = row_pixels[0];
      int center = row_pixels[1];
      for (int x = 1; x < width - 1; x++) {
          int right = row_pixels[x + 1];
          // A simple -1 4 -1 box filter with a weight of 2.
          int luminance = ((center << 2) - left - right) >> 1;
          if (luminance < blackPoint) {
              array.set(x);
          }
          left = center;
          center = right;
      }

      cached_row_ = array_ref;
      cached_row_num_ = y;
      delete [] row_pixels;
      return array_ref;
  } catch (IllegalArgumentException const& iae) {
      // Cache the fact that this row failed.
      cached_row_ = NULL;
      cached_row_num_ = y;
      delete [] row_pixels;
      throw iae;
  }
}

Ref<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix() {
  if (cached_matrix_ != NULL) {
    return cached_matrix_;
  }

  // Faster than working with the reference
  LuminanceSource& source = *getLuminanceSource();
  int width = source.getWidth();
  int height = source.getHeight();
  vector<int> histogram(LUMINANCE_BUCKETS, 0);

  // Quickly calculates the histogram by sampling four rows from the image.
  // This proved to be more robust on the blackbox tests than sampling a
  // diagonal as we used to do.
  unsigned char* row = new unsigned char[width];
  for (int y = 1; y < 5; y++) {
    int rownum = height * y / 5;
    int right = (width << 2) / 5;
    int sdf;
    getLuminanceSource()->getRow(rownum,row);
    for (int x = width / 5; x < right; x++) {
      histogram[row[x] >> LUMINANCE_SHIFT]++;
      sdf = histogram[row[x] >> LUMINANCE_SHIFT];
    }
  }

  int blackPoint = estimate(histogram) << LUMINANCE_SHIFT;

  Ref<BitMatrix> matrix_ref(new BitMatrix(width, height));
  BitMatrix& matrix = *matrix_ref;
  for (int y = 0; y < height; y++) {
    getLuminanceSource()->getRow(y,row);
    for (int x = 0; x < width; x++) {
      if (row[x] <= blackPoint)
        matrix.set(x, y);
    }
  }

  cached_matrix_ = matrix_ref;

  delete [] row;
  return matrix_ref;
}

int GlobalHistogramBinarizer::estimate(vector<int> &histogram) {
  int numBuckets = histogram.size();
  int maxBucketCount = 0;

  // Find tallest peak in histogram
  int firstPeak = 0;
  int firstPeakSize = 0;
  for (int i = 0; i < numBuckets; i++) {
    if (histogram[i] > firstPeakSize) {
      firstPeak = i;
      firstPeakSize = histogram[i];
    }
    if (histogram[i] > maxBucketCount) {
      maxBucketCount = histogram[i];
    }
  }

  // Find second-tallest peak -- well, another peak that is tall and not
  // so close to the first one
  int secondPeak = 0;
  int secondPeakScore = 0;
  for (int i = 0; i < numBuckets; i++) {
    int distanceToBiggest = i - firstPeak;
    // Encourage more distant second peaks by multiplying by square of distance
    int score = histogram[i] * distanceToBiggest * distanceToBiggest;
    if (score > secondPeakScore) {
      secondPeak = i;
      secondPeakScore = score;
    }
  }

  // Put firstPeak first
  if (firstPeak > secondPeak) {
    int temp = firstPeak;
    firstPeak = secondPeak;
    secondPeak = temp;
  }

  // Kind of arbitrary; if the two peaks are very close, then we figure there is
  // so little dynamic range in the image, that discriminating black and white
  // is too error-prone.
  // Decoding the image/line is either pointless, or may in some cases lead to
  // a false positive for 1D formats, which are relatively lenient.
  // We arbitrarily say "close" is
  // "<= 1/16 of the total histogram buckets apart"
  if (secondPeak - firstPeak <= numBuckets >> 4) {
    throw IllegalArgumentException("Too little dynamic range in luminance");
  }

  // Find a valley between them that is low and closer to the white peak
  int bestValley = secondPeak - 1;
  int bestValleyScore = -1;
  for (int i = secondPeak - 1; i > firstPeak; i--) {
    int fromFirst = i - firstPeak;
    // Favor a "valley" that is not too close to either peak -- especially not
    // the black peak -- and that has a low value of course
    int score = fromFirst * fromFirst * (secondPeak - i) *
      (maxBucketCount - histogram[i]);
    if (score > bestValleyScore) {
      bestValley = i;
      bestValleyScore = score;
    }
  }

  return bestValley;
}

Ref<Binarizer> GlobalHistogramBinarizer::createBinarizer(Ref<LuminanceSource> source) {
  return Ref<Binarizer> (new GlobalHistogramBinarizer(source));
}

} // namespace zxing

<|endoftext|>


<commit_before>
#include "robot.hpp"
#include "console.hpp"
#include "commands.hpp"
#include "logger.hpp"
#include "radio.hpp"

LocalFileSystem local("local");

Ticker lifeLight;
DigitalOut ledOne(LED1);
DigitalOut ledTwo(LED2);

/*
 * some forward declarations to make the code easier to read
 */
void imAlive(void);
void setISRPriorities(void);
void initRadioThread(void);
void initConsoleRoutine(void);
void fpgaInit();

/**
 * system entry point
 */
int main(void)
{
	//setISRPriorities();
	lifeLight.attach(&imAlive, 0.25);

	isLogging = true;
	rjLogLevel = INF2;

	//initRadioThread();
	//initConsoleRoutine();

    fpgaInit();
}

/**
 * Initializes the peripheral nested vector interrupt controller (PNVIC) with
 * appropriate values. Low values have the higest priority (with system
 * interrupts having negative priority). All maskable interrupts are
 * diabled; do not intialize any interrupt frameworks before this funtion is
 * called. PNVIC interrupt priorities are independent of thread and NVIC
 * priorities.
 *
 * The PNVIC is independent of the NVIC responsible for system NMI's. The NVIC
 * is not accissable through the library, so in this context the NVIC functions
 * refer to the PNVIC. The configuration system for PNVIC priorities is strange
 * and different from X86. If you haven't already, look over
 * doc/ARM-Cortex-M_Interrupt-Priorities.pdf from RJ root and the online
 * documentation regarding Interrupt Priority Registers (IPRs) first.
 */
void setISRPriorities(void)
{
	//set two bits for preemptive data, two bits for priority as the
	//structure for the IPRs. Grouping is global withing the IPRs so
	//this value should only be changed here.
	NVIC_SetPriorityGrouping(5);
	uint32_t priorityGrouping = NVIC_GetPriorityGrouping();

	//set preemptive priority default to 2 (0..3)
	//set priority default to 1 (0..3)
	uint32_t defaultPriority = NVIC_EncodePriority(priorityGrouping, 2, 1);

	//When the kernel initialzes the PNVIC, all ISRs are set to the
	//highest priority, making it impossible to elevate a few over
	//the rest, so the default priority is lowered globally for the
	//table first.
	//
	//Consult LPC17xx.h under IRQn_Type for PNVIC ranges, this is LPC1768
	//specific
	for (uint32_t IRQn = TIMER0_IRQn; IRQn <= CANActivity_IRQn; IRQn++)
	{
		//set default priority
		NVIC_SetPriority((IRQn_Type) IRQn, defaultPriority);
	}

	////////////////////////////////////
	//  begin raise priority section  //
	////////////////////////////////////

	//reestablish watchdog
	NVIC_SetPriority(WDT_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 0));

	//TODO raise radio
	//TODO raise others after discussion

	////////////////////////////////////
	//  begin lower priotity section  //
	////////////////////////////////////

	//set UART (console) interrupts to minimal priority
	//when debugging radio and other time sensitive operations, this
	//interrupt will need to be deferred, especially given the number of
	//calls to printf()
	NVIC_SetPriority(UART0_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 0));
	NVIC_SetPriority(UART1_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
	NVIC_SetPriority(UART2_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
	NVIC_SetPriority(UART3_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 1));

	//TODO lower others after discussion

	//NVIC_EnableIRQ(TIMER0_IRQn);
	//NVIC_EnableIRQ(TIMER1_IRQn);
	//NVIC_EnableIRQ(TIMER2_IRQn);
	//NVIC_EnableIRQ(TIMER3_IRQn);
}

/**
 * initializes the radio communications thread
 */
void initRadioThread(void)
{
	initRadio();
}

/**
 * initializes the console
 */
void initConsoleRoutine(void)
{
	if (!COMPETITION_DEPLOY)
	{
		initConsole();

		for (;;)
		{
			//check console communications, currently does nothing
			//then execute any active iterative command
			conComCheck();
			//execute any active iterative command
			executeIterativeCommand();

			//check if a system stop is requested
			if (isSysStopReq() == true)
			{
				break;
			}

			//main loop heartbeat
			wait(0.1);
			ledTwo = !ledTwo;
	    	}

		//clear light for main loop (shows its complete)
		ledTwo = false;
	}
	else
	{
		for (;;);
	}
}

void fpgaInit() {
    //  mosi, miso, sclk - connected to fpga
    SPI spi(p5, p6, p7);
    DigitalOut fpgaCs(p18); //  chip select for SPI to fpga
    DigitalOut fpga_prog_b(p24);

    fpga_prog_b = 1;
    wait(1);    //  1 second
    fpga_prog_b = 0;
    wait_us(80);
    fpga_prog_b = 1;

    //  8 bits per write, mode 3?
    spi.format(8, 3);

    //  1MHz - pretty slow, we can boost this later
    //  our max physical limit is 1/8 of the fpga system clock (18.4MHz), so 18.4/8 is the max
    spi.frequency(1000000);

    FILE *fp = fopen("/local/robocup.nib", "r");

    printf("opened file: %p\r\n", fp);

    int result = 0;
    char buf[10];
    while (true) {
        size_t bytes_read = fread(buf, 1, 1, fp);
        if (bytes_read == 0) break;
        // printf("writing: %d...\r\n", buf[0]);
        result = spi.write(buf[0]); //  result should always be 0xFF since it's wired to high
    }

    fclose(fp);

    printf("got final byte from spi: %x\r\n", result);
}

/**
 * timer interrupt based light flicker. If this stops, the code triggered
 * a fault.
 */
void imAlive()
{
	ledOne = !ledOne;
}
<commit_msg>mainnnnn<commit_after>
#include "robot.hpp"
#include "console.hpp"
#include "commands.hpp"
#include "logger.hpp"
#include "radio.hpp"

#define READ_SPI_16	0x8000
#define SET_ADDR( x ) ((x)<<11)

LocalFileSystem local("local");

Ticker lifeLight;
DigitalOut ledOne(LED1);
DigitalOut ledTwo(LED2);
DigitalOut drv_ncs(p20,1);
DigitalOut drv_en(p19,1);

//  mosi, miso, sclk - connected to fpga
SPI spi(p5, p6, p7);

/*
 * some forward declarations to make the code easier to read
 */
void imAlive(void);
void setISRPriorities(void);
void initRadioThread(void);
void initConsoleRoutine(void);
void fpgaInit();

/**
 * system entry point
 */
int main(void)
{
	//setISRPriorities();
	lifeLight.attach(&imAlive, 0.25);

	isLogging = true;
	rjLogLevel = INF2;

	//initRadioThread();
	//initConsoleRoutine();

    fpgaInit();

    spi.format(16,0);

    uint16_t reg_config [2];
    reg_config[0] = READ_SPI_16 | SET_ADDR(2) | (6<<6);
    reg_config[1] = READ_SPI_16 | SET_ADDR(3) | (1<<5) | (1<<4);

    for (int i=0; i<2; i++)
    	spi.write(reg_config[i]);

    uint16_t reg_vals[2];

    while(1)
    {

    	for (int i=0; i<2; i++)
    		reg_vals[i] = 0x3FF & spi.write(SET_ADDR(i));
/*
    	bool fault = reg_vals[0]>>10;
    	bool gvdd_uv = reg_vals[0]>>9;
    	bool pvdd_uv = reg_vals[0]>>8;
    	bool otsd = reg_vals[0]>>7;
    	bool otw = reg_vals[0]>>6;
    	bool ah_oc = reg_vals[0]>>5;
    	bool al_oc = reg_vals[0]>>4;
    	bool bh_oc = reg_vals[0]>>3;
    	bool bl_oc = reg_vals[0]>>2;
    	bool ah_oc = reg_vals[0]>>1;
    	bool al_oc = reg_vals[0];
    	*/

/*
    	printf("Fault:\t%u", fault);
    	printf("GVDD_UV\t%u", gvdd_uv);
    	printf("PVDD_UV\t%u", pvdd_uv);
    	printf("GVDD_UV\t%u", );
    	printf("GVDD_UV\t%u", gvdd_uv);
    	*/

    	printf("Address 0x00:\t0x%04X\r\nAddress 0x01:\t0x%04X\r\n", reg_vals[0], reg_vals[1]);
    	wait(2);
    }

}

/**
 * Initializes the peripheral nested vector interrupt controller (PNVIC) with
 * appropriate values. Low values have the higest priority (with system
 * interrupts having negative priority). All maskable interrupts are
 * diabled; do not intialize any interrupt frameworks before this funtion is
 * called. PNVIC interrupt priorities are independent of thread and NVIC
 * priorities.
 *
 * The PNVIC is independent of the NVIC responsible for system NMI's. The NVIC
 * is not accissable through the library, so in this context the NVIC functions
 * refer to the PNVIC. The configuration system for PNVIC priorities is strange
 * and different from X86. If you haven't already, look over
 * doc/ARM-Cortex-M_Interrupt-Priorities.pdf from RJ root and the online
 * documentation regarding Interrupt Priority Registers (IPRs) first.
 */
void setISRPriorities(void)
{
	//set two bits for preemptive data, two bits for priority as the
	//structure for the IPRs. Grouping is global withing the IPRs so
	//this value should only be changed here.
	NVIC_SetPriorityGrouping(5);
	uint32_t priorityGrouping = NVIC_GetPriorityGrouping();

	//set preemptive priority default to 2 (0..3)
	//set priority default to 1 (0..3)
	uint32_t defaultPriority = NVIC_EncodePriority(priorityGrouping, 2, 1);

	//When the kernel initialzes the PNVIC, all ISRs are set to the
	//highest priority, making it impossible to elevate a few over
	//the rest, so the default priority is lowered globally for the
	//table first.
	//
	//Consult LPC17xx.h under IRQn_Type for PNVIC ranges, this is LPC1768
	//specific
	for (uint32_t IRQn = TIMER0_IRQn; IRQn <= CANActivity_IRQn; IRQn++)
	{
		//set default priority
		NVIC_SetPriority((IRQn_Type) IRQn, defaultPriority);
	}

	////////////////////////////////////
	//  begin raise priority section  //
	////////////////////////////////////

	//reestablish watchdog
	NVIC_SetPriority(WDT_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 0));

	//TODO raise radio
	//TODO raise others after discussion

	////////////////////////////////////
	//  begin lower priotity section  //
	////////////////////////////////////

	//set UART (console) interrupts to minimal priority
	//when debugging radio and other time sensitive operations, this
	//interrupt will need to be deferred, especially given the number of
	//calls to printf()
	NVIC_SetPriority(UART0_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 0));
	NVIC_SetPriority(UART1_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
	NVIC_SetPriority(UART2_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
	NVIC_SetPriority(UART3_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 1));

	//TODO lower others after discussion

	//NVIC_EnableIRQ(TIMER0_IRQn);
	//NVIC_EnableIRQ(TIMER1_IRQn);
	//NVIC_EnableIRQ(TIMER2_IRQn);
	//NVIC_EnableIRQ(TIMER3_IRQn);
}

/**
 * initializes the radio communications thread
 */
void initRadioThread(void)
{
	initRadio();
}

/**
 * initializes the console
 */
void initConsoleRoutine(void)
{
	if (!COMPETITION_DEPLOY)
	{
		initConsole();

		for (;;)
		{
			//check console communications, currently does nothing
			//then execute any active iterative command
			conComCheck();
			//execute any active iterative command
			executeIterativeCommand();

			//check if a system stop is requested
			if (isSysStopReq() == true)
			{
				break;
			}

			//main loop heartbeat
			wait(0.1);
			ledTwo = !ledTwo;
	    	}

		//clear light for main loop (shows its complete)
		ledTwo = false;
	}
	else
	{
		for (;;);
	}
}

void fpgaInit() {
    DigitalOut fpgaCs(p18); //  chip select for SPI to fpga
    DigitalOut fpga_prog_b(p24);

    fpga_prog_b = 1;
    wait(1);    //  1 second
    fpga_prog_b = 0;
    wait_us(80);
    fpga_prog_b = 1;

    //  8 bits per write, mode 3?
    spi.format(8, 3);

    //  1MHz - pretty slow, we can boost this later
    //  our max physical limit is 1/8 of the fpga system clock (18.4MHz), so 18.4/8 is the max
    spi.frequency(1000000);

    FILE *fp = fopen("/local/robocup.nib", "r");

    printf("opened file: %p\r\n", fp);

    int result = 0;
    char buf[10];
    while (true) {
        size_t bytes_read = fread(buf, 1, 1, fp);
        if (bytes_read == 0) break;
        // printf("writing: %d...\r\n", buf[0]);
        result = spi.write(buf[0]); //  result should always be 0xFF since it's wired to high
    }

    fclose(fp);

    printf("got final byte from spi: %x\r\n\tFPGA configured!\r\n", result);
}

/**
 * timer interrupt based light flicker. If this stops, the code triggered
 * a fault.
 */
void imAlive()
{
	ledOne = !ledOne;
}
<|endoftext|>


<commit_before>#include "routing_engine.hpp"
#include "route.hpp"
#include "helicopter_router.hpp"

#include "../base/stl_add.hpp"
#include "../base/logging.hpp"

namespace routing
{

RoutingEngine::RoutingEngine()
{
  m_pointStates[0] = m_pointStates[1] = INVALID;
}

RoutingEngine::~RoutingEngine()
{
  for_each(m_routers.begin(), m_routers.end(), DeleteFunctor());
}

void RoutingEngine::AddRouter(string const & name)
{
  if (!FindRouter(name) && name == "helicopter")
    m_routers.push_back(new HelicopterRouter);
}

void RoutingEngine::RemoveRouter(string const & name)
{
  for (TRouters::iterator it = m_routers.begin(); it != m_routers.end(); ++it)
  {
    IRouter * router = *it;
    if (router->GetName() == name)
    {
      m_routers.erase(it);
      delete router;
      break;
    }
  }
}

bool RoutingEngine::IsRoutingEnabled() const
{
  return !m_routers.empty();
}

void RoutingEngine::SetStartingPoint(m2::PointD const & pt)
{
  if (m_pointStates[0] == INVALID || !my::AlmostEqual(m_points[0], pt))
  {
    m_points[0] = pt;
    m_pointStates[0] = MODIFIED;
  }
}

void RoutingEngine::SetFinalPoint(m2::PointD const & pt)
{
  if (m_pointStates[1] == INVALID || !my::AlmostEqual(m_points[1], pt))
  {
    m_points[1] = pt;
    m_pointStates[1] = MODIFIED;
  }
}

void RoutingEngine::Calculate(string const & name, IRouter::ReadyCallback const & callback)
{
  IRouter * p = FindRouter(name);
  if (!p)
  {
    LOG(LWARNING, ("Can't calculate route - router engine", name, "is not initialized."));
    return;
  }

  if (m_pointStates[0] == INVALID || m_pointStates[1] == INVALID)
  {
    LOG(LINFO, ("Routing calculation cancelled - start and/or end points are not initialized."));
    return;
  }

  if (m_pointStates[0] != MODIFIED || m_pointStates[1] != MODIFIED)
  {
    LOG(LINFO, ("Routing calculation cancelled - start and end points are the same."));
    return;
  }

  if (m_pointStates[1] == MODIFIED)
    p->SetFinalPoint(m_points[1]);

  p->CalculateRoute(m_points[0], callback);
}

IRouter * RoutingEngine::FindRouter(string const & name)
{
  for (size_t i = 0; i < m_routers.size(); ++i)
    if (m_routers[i]->GetName() == name)
      return m_routers[i];
  return 0;
}

} // namespace routing
<commit_msg>[routing] Fixed OSRM initialization<commit_after>#include "routing_engine.hpp"
#include "route.hpp"
#include "helicopter_router.hpp"
#include "osrm_router.hpp"

#include "../base/stl_add.hpp"
#include "../base/logging.hpp"

namespace routing
{

RoutingEngine::RoutingEngine()
{
  m_pointStates[0] = m_pointStates[1] = INVALID;
}

RoutingEngine::~RoutingEngine()
{
  for_each(m_routers.begin(), m_routers.end(), DeleteFunctor());
}

void RoutingEngine::AddRouter(string const & name)
{
  if (!FindRouter(name))
  {
    if (name == "helicopter")
      m_routers.push_back(new HelicopterRouter);
    else if (name == "osrm")
      m_routers.push_back(new OsrmRouter);
  }
}

void RoutingEngine::RemoveRouter(string const & name)
{
  for (TRouters::iterator it = m_routers.begin(); it != m_routers.end(); ++it)
  {
    IRouter * router = *it;
    if (router->GetName() == name)
    {
      m_routers.erase(it);
      delete router;
      break;
    }
  }
}

bool RoutingEngine::IsRoutingEnabled() const
{
  return !m_routers.empty();
}

void RoutingEngine::SetStartingPoint(m2::PointD const & pt)
{
  if (m_pointStates[0] == INVALID || !my::AlmostEqual(m_points[0], pt))
  {
    m_points[0] = pt;
    m_pointStates[0] = MODIFIED;
  }
}

void RoutingEngine::SetFinalPoint(m2::PointD const & pt)
{
  if (m_pointStates[1] == INVALID || !my::AlmostEqual(m_points[1], pt))
  {
    m_points[1] = pt;
    m_pointStates[1] = MODIFIED;
  }
}

void RoutingEngine::Calculate(string const & name, IRouter::ReadyCallback const & callback)
{
  if (name == "all")
  {
    for (size_t i = 0; i < m_routers.size(); ++i)
      Calculate(m_routers[i]->GetName(), callback);
    return;
  }

  IRouter * p = FindRouter(name);
  if (!p)
  {
    LOG(LWARNING, ("Can't calculate route - router engine", name, "is not initialized."));
    return;
  }

  if (m_pointStates[0] == INVALID || m_pointStates[1] == INVALID)
  {
    LOG(LINFO, ("Routing calculation cancelled - start and/or end points are not initialized."));
    return;
  }

  if (m_pointStates[0] != MODIFIED || m_pointStates[1] != MODIFIED)
  {
    LOG(LINFO, ("Routing calculation cancelled - start and end points are the same."));
    return;
  }

  if (m_pointStates[1] == MODIFIED)
    p->SetFinalPoint(m_points[1]);

  p->CalculateRoute(m_points[0], callback);
}

IRouter * RoutingEngine::FindRouter(string const & name)
{
  for (size_t i = 0; i < m_routers.size(); ++i)
    if (m_routers[i]->GetName() == name)
      return m_routers[i];
  return 0;
}

} // namespace routing
<|endoftext|>


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

#ifndef DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP
#define DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP

#include <DTK_Box.hpp>
#include <DTK_DetailsDistributedSearchTreeImpl.hpp>
#include <DTK_DetailsUtils.hpp> // accumulate
#include <DTK_LinearBVH.hpp>

#include <Kokkos_View.hpp>

#include <mpi.h>

namespace DataTransferKit
{

/** \brief Distributed search tree
 *
 *  \note query() must be called as collective over all processes in the
 *  communicator passed to the constructor.
 */
template <typename DeviceType>
class DistributedSearchTree
{
  public:
    using bounding_volume_type = typename BVH<DeviceType>::bounding_volume_type;
    using size_type = typename BVH<DeviceType>::size_type;

    template <typename Primitives>
    DistributedSearchTree( MPI_Comm comm, Primitives const &primitives );

    /** Returns the smallest axis-aligned box able to contain all the objects
     *  stored in the tree or an invalid box if the tree is empty.
     */
    bounding_volume_type bounds() const { return _top_tree.bounds(); }

    /** Returns the global number of objects stored in the tree.
     */
    size_type size() const { return _top_tree_size; }

    /** Indicates whether the tree is empty on all processes.
     */
    bool empty() const { return size() == 0; }

    /** \brief Finds object satisfying the passed predicates (e.g. nearest to
     *  some point or overlaping with some box)
     *
     *  This query function performs a batch of spatial or k-nearest neighbors
     *  searches.  The results give indices of the objects that satisfy
     *  predicates (as given to the constructor).  They are organized in a
     *  distributed compressed row storage format.
     *
     *  \c indices stores the indices of the objects that satisfy the
     *  predicates.  \c offset stores the locations in the \c indices view that
     *  start a predicate, that is, \c queries(q) is satisfied by \c indices(o)
     *  for objects(q) <= o < objects(q+1) that live on processes
     *  \c ranks(o) respectively.  Following the usual convention,
     *  offset(n) = nnz, where \c n is the number of queries that
     *  were performed and \c nnz is the total number of collisions.
     *
     *  \note The views \c indices, \c offset, and \c ranks are passed by
     *  reference because \c Kokkos::realloc() calls the assignment operator.
     *
     *  \param[in] predicates Collection of predicates of the same type.  These
     *  may be spatial predicates or nearest predicates.
     *  \param[out] args
     *     - \c indices Object local indices that satisfy the predicates.
     *     - \c offset Array of predicate offsets for one-dimensional
     *       storage.
     *     - \c ranks Process ranks that own objects.
     *     - \c distances Computed distances (optional and only for nearest
     *       predicates).
     */
    template <typename Predicates, typename... Args>
    void query( Predicates const &predicates, Args &&... args ) const
    {
        // FIXME lame placeholder for concept check
        static_assert( Kokkos::is_view<Predicates>::value, "must pass a view" );
        using Tag = typename Predicates::value_type::Tag;
        Details::DistributedSearchTreeImpl<DeviceType>::queryDispatch(
            Tag{}, *this, predicates, std::forward<Args>( args )... );
    }

  private:
    friend struct Details::DistributedSearchTreeImpl<DeviceType>;
    MPI_Comm _comm;
    BVH<DeviceType> _top_tree;    // replicated
    BVH<DeviceType> _bottom_tree; // local
    size_type _top_tree_size;
    Kokkos::View<size_type *, DeviceType> _bottom_tree_sizes;
};

template <typename DeviceType>
template <typename Primitives>
DistributedSearchTree<DeviceType>::DistributedSearchTree(
    MPI_Comm comm, Primitives const &primitives )
    : _comm( comm )
    , _bottom_tree( primitives )
{
    int comm_rank;
    MPI_Comm_rank( _comm, &comm_rank );
    int comm_size;
    MPI_Comm_size( _comm, &comm_size );

    Kokkos::View<Box *, DeviceType> boxes(
        Kokkos::ViewAllocateWithoutInitializing( "rank_bounding_boxes" ),
        comm_size );
    // FIXME when we move to MPI with CUDA-aware support, we will not need to
    // copy from the device to the host
    auto boxes_host = Kokkos::create_mirror_view( boxes );
    boxes_host( comm_rank ) = _bottom_tree.bounds();
    MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
                   static_cast<void *>( boxes_host.data() ), sizeof( Box ),
                   MPI_BYTE, _comm );
    Kokkos::deep_copy( boxes, boxes_host );

    _top_tree = BVH<DeviceType>( boxes );

    _bottom_tree_sizes = Kokkos::View<size_type *, DeviceType>(
        Kokkos::ViewAllocateWithoutInitializing( "leave_count_in_local_trees" ),
        comm_size );
    auto bottom_tree_sizes_host =
        Kokkos::create_mirror_view( _bottom_tree_sizes );
    bottom_tree_sizes_host( comm_rank ) = _bottom_tree.size();
    MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
                   static_cast<void *>( bottom_tree_sizes_host.data() ),
                   sizeof( size_type ), MPI_BYTE, _comm );
    Kokkos::deep_copy( _bottom_tree_sizes, bottom_tree_sizes_host );

    _top_tree_size = accumulate( _bottom_tree_sizes, 0 );
}

} // namespace DataTransferKit

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

#ifndef DTK_DISTRIBUTED_SEARCH_TREE_HPP
#define DTK_DISTRIBUTED_SEARCH_TREE_HPP

#include <DTK_Box.hpp>
#include <DTK_DetailsDistributedSearchTreeImpl.hpp>
#include <DTK_DetailsUtils.hpp> // accumulate
#include <DTK_LinearBVH.hpp>

#include <Kokkos_View.hpp>

#include <mpi.h>

namespace DataTransferKit
{

/** \brief Distributed search tree
 *
 *  \note query() must be called as collective over all processes in the
 *  communicator passed to the constructor.
 */
template <typename DeviceType>
class DistributedSearchTree
{
  public:
    using bounding_volume_type = typename BVH<DeviceType>::bounding_volume_type;
    using size_type = typename BVH<DeviceType>::size_type;

    template <typename Primitives>
    DistributedSearchTree( MPI_Comm comm, Primitives const &primitives );

    /** Returns the smallest axis-aligned box able to contain all the objects
     *  stored in the tree or an invalid box if the tree is empty.
     */
    bounding_volume_type bounds() const { return _top_tree.bounds(); }

    /** Returns the global number of objects stored in the tree.
     */
    size_type size() const { return _top_tree_size; }

    /** Indicates whether the tree is empty on all processes.
     */
    bool empty() const { return size() == 0; }

    /** \brief Finds object satisfying the passed predicates (e.g. nearest to
     *  some point or overlaping with some box)
     *
     *  This query function performs a batch of spatial or k-nearest neighbors
     *  searches.  The results give indices of the objects that satisfy
     *  predicates (as given to the constructor).  They are organized in a
     *  distributed compressed row storage format.
     *
     *  \c indices stores the indices of the objects that satisfy the
     *  predicates.  \c offset stores the locations in the \c indices view that
     *  start a predicate, that is, \c queries(q) is satisfied by \c indices(o)
     *  for objects(q) <= o < objects(q+1) that live on processes
     *  \c ranks(o) respectively.  Following the usual convention,
     *  offset(n) = nnz, where \c n is the number of queries that
     *  were performed and \c nnz is the total number of collisions.
     *
     *  \note The views \c indices, \c offset, and \c ranks are passed by
     *  reference because \c Kokkos::realloc() calls the assignment operator.
     *
     *  \param[in] predicates Collection of predicates of the same type.  These
     *  may be spatial predicates or nearest predicates.
     *  \param[out] args
     *     - \c indices Object local indices that satisfy the predicates.
     *     - \c offset Array of predicate offsets for one-dimensional
     *       storage.
     *     - \c ranks Process ranks that own objects.
     *     - \c distances Computed distances (optional and only for nearest
     *       predicates).
     */
    template <typename Predicates, typename... Args>
    void query( Predicates const &predicates, Args &&... args ) const
    {
        // FIXME lame placeholder for concept check
        static_assert( Kokkos::is_view<Predicates>::value, "must pass a view" );
        using Tag = typename Predicates::value_type::Tag;
        Details::DistributedSearchTreeImpl<DeviceType>::queryDispatch(
            Tag{}, *this, predicates, std::forward<Args>( args )... );
    }

  private:
    friend struct Details::DistributedSearchTreeImpl<DeviceType>;
    MPI_Comm _comm;
    BVH<DeviceType> _top_tree;    // replicated
    BVH<DeviceType> _bottom_tree; // local
    size_type _top_tree_size;
    Kokkos::View<size_type *, DeviceType> _bottom_tree_sizes;
};

template <typename DeviceType>
template <typename Primitives>
DistributedSearchTree<DeviceType>::DistributedSearchTree(
    MPI_Comm comm, Primitives const &primitives )
    : _comm( comm )
    , _bottom_tree( primitives )
{
    int comm_rank;
    MPI_Comm_rank( _comm, &comm_rank );
    int comm_size;
    MPI_Comm_size( _comm, &comm_size );

    Kokkos::View<Box *, DeviceType> boxes(
        Kokkos::ViewAllocateWithoutInitializing( "rank_bounding_boxes" ),
        comm_size );
    // FIXME when we move to MPI with CUDA-aware support, we will not need to
    // copy from the device to the host
    auto boxes_host = Kokkos::create_mirror_view( boxes );
    boxes_host( comm_rank ) = _bottom_tree.bounds();
    MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
                   static_cast<void *>( boxes_host.data() ), sizeof( Box ),
                   MPI_BYTE, _comm );
    Kokkos::deep_copy( boxes, boxes_host );

    _top_tree = BVH<DeviceType>( boxes );

    _bottom_tree_sizes = Kokkos::View<size_type *, DeviceType>(
        Kokkos::ViewAllocateWithoutInitializing( "leave_count_in_local_trees" ),
        comm_size );
    auto bottom_tree_sizes_host =
        Kokkos::create_mirror_view( _bottom_tree_sizes );
    bottom_tree_sizes_host( comm_rank ) = _bottom_tree.size();
    MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
                   static_cast<void *>( bottom_tree_sizes_host.data() ),
                   sizeof( size_type ), MPI_BYTE, _comm );
    Kokkos::deep_copy( _bottom_tree_sizes, bottom_tree_sizes_host );

    _top_tree_size = accumulate( _bottom_tree_sizes, 0 );
}

} // namespace DataTransferKit

#endif
<|endoftext|>


<commit_before>/*
 *  Copyright 2016 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/task_queue_win.h"

// clang-format off
// clang formating would change include order.

// Include winsock2.h before including <windows.h> to maintain consistency with
// win32.h. To include win32.h directly, it must be broken out into its own
// build target.
#include <winsock2.h>
#include <windows.h>
#include <sal.h>       // Must come after windows headers.
#include <mmsystem.h>  // Must come after windows headers.
// clang-format on
#include <string.h>

#include <algorithm>
#include <memory>
#include <queue>
#include <utility>

#include "absl/strings/string_view.h"
#include "api/task_queue/queued_task.h"
#include "api/task_queue/task_queue_base.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/time_utils.h"

namespace webrtc {
namespace {
#define WM_RUN_TASK WM_USER + 1
#define WM_QUEUE_DELAYED_TASK WM_USER + 2

void CALLBACK InitializeQueueThread(ULONG_PTR param) {
  MSG msg;
  ::PeekMessage(&msg, nullptr, WM_USER, WM_USER, PM_NOREMOVE);
  rtc::Event* data = reinterpret_cast<rtc::Event*>(param);
  data->Set();
}

rtc::ThreadPriority TaskQueuePriorityToThreadPriority(
    TaskQueueFactory::Priority priority) {
  switch (priority) {
    case TaskQueueFactory::Priority::HIGH:
      return rtc::kRealtimePriority;
    case TaskQueueFactory::Priority::LOW:
      return rtc::kLowPriority;
    case TaskQueueFactory::Priority::NORMAL:
      return rtc::kNormalPriority;
    default:
      RTC_NOTREACHED();
      break;
  }
  return rtc::kNormalPriority;
}

int64_t GetTick() {
  static const UINT kPeriod = 1;
  bool high_res = (timeBeginPeriod(kPeriod) == TIMERR_NOERROR);
  int64_t ret = rtc::TimeMillis();
  if (high_res)
    timeEndPeriod(kPeriod);
  return ret;
}

class DelayedTaskInfo {
 public:
  // Default ctor needed to support priority_queue::pop().
  DelayedTaskInfo() {}
  DelayedTaskInfo(uint32_t milliseconds, std::unique_ptr<QueuedTask> task)
      : due_time_(GetTick() + milliseconds), task_(std::move(task)) {}
  DelayedTaskInfo(DelayedTaskInfo&&) = default;

  // Implement for priority_queue.
  bool operator>(const DelayedTaskInfo& other) const {
    return due_time_ > other.due_time_;
  }

  // Required by priority_queue::pop().
  DelayedTaskInfo& operator=(DelayedTaskInfo&& other) = default;

  // See below for why this method is const.
  void Run() const {
    RTC_DCHECK(due_time_);
    task_->Run() ? task_.reset() : static_cast<void>(task_.release());
  }

  int64_t due_time() const { return due_time_; }

 private:
  int64_t due_time_ = 0;  // Absolute timestamp in milliseconds.

  // |task| needs to be mutable because std::priority_queue::top() returns
  // a const reference and a key in an ordered queue must not be changed.
  // There are two basic workarounds, one using const_cast, which would also
  // make the key (|due_time|), non-const and the other is to make the non-key
  // (|task|), mutable.
  // Because of this, the |task| variable is made private and can only be
  // mutated by calling the |Run()| method.
  mutable std::unique_ptr<QueuedTask> task_;
};

class MultimediaTimer {
 public:
  // Note: We create an event that requires manual reset.
  MultimediaTimer() : event_(::CreateEvent(nullptr, true, false, nullptr)) {}

  ~MultimediaTimer() {
    Cancel();
    ::CloseHandle(event_);
  }

  bool StartOneShotTimer(UINT delay_ms) {
    RTC_DCHECK_EQ(0, timer_id_);
    RTC_DCHECK(event_ != nullptr);
    timer_id_ =
        ::timeSetEvent(delay_ms, 0, reinterpret_cast<LPTIMECALLBACK>(event_), 0,
                       TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
    return timer_id_ != 0;
  }

  void Cancel() {
    ::ResetEvent(event_);
    if (timer_id_) {
      ::timeKillEvent(timer_id_);
      timer_id_ = 0;
    }
  }

  HANDLE* event_for_wait() { return &event_; }

 private:
  HANDLE event_ = nullptr;
  MMRESULT timer_id_ = 0;

  RTC_DISALLOW_COPY_AND_ASSIGN(MultimediaTimer);
};

class TaskQueueWin : public TaskQueueBase {
 public:
  TaskQueueWin(absl::string_view queue_name, rtc::ThreadPriority priority);
  ~TaskQueueWin() override = default;

  void Delete() override;
  void PostTask(std::unique_ptr<QueuedTask> task) override;
  void PostDelayedTask(std::unique_ptr<QueuedTask> task,
                       uint32_t milliseconds) override;

  void RunPendingTasks();

 private:
  static void ThreadMain(void* context);

  class WorkerThread : public rtc::PlatformThread {
   public:
    WorkerThread(rtc::ThreadRunFunction func,
                 void* obj,
                 absl::string_view thread_name,
                 rtc::ThreadPriority priority)
        : PlatformThread(func, obj, thread_name, priority) {}

    bool QueueAPC(PAPCFUNC apc_function, ULONG_PTR data) {
      return rtc::PlatformThread::QueueAPC(apc_function, data);
    }
  };

  void RunThreadMain();
  bool ProcessQueuedMessages();
  void RunDueTasks();
  void ScheduleNextTimer();
  void CancelTimers();

  // Since priority_queue<> by defult orders items in terms of
  // largest->smallest, using std::less<>, and we want smallest->largest,
  // we would like to use std::greater<> here. Alas it's only available in
  // C++14 and later, so we roll our own compare template that that relies on
  // operator<().
  template <typename T>
  struct greater {
    bool operator()(const T& l, const T& r) { return l > r; }
  };

  MultimediaTimer timer_;
  std::priority_queue<DelayedTaskInfo,
                      std::vector<DelayedTaskInfo>,
                      greater<DelayedTaskInfo>>
      timer_tasks_;
  UINT_PTR timer_id_ = 0;
  WorkerThread thread_;
  rtc::CriticalSection pending_lock_;
  std::queue<std::unique_ptr<QueuedTask>> pending_
      RTC_GUARDED_BY(pending_lock_);
  HANDLE in_queue_;
};

TaskQueueWin::TaskQueueWin(absl::string_view queue_name,
                           rtc::ThreadPriority priority)
    : thread_(&TaskQueueWin::ThreadMain, this, queue_name, priority),
      in_queue_(::CreateEvent(nullptr, true, false, nullptr)) {
  RTC_DCHECK(in_queue_);
  thread_.Start();
  rtc::Event event(false, false);
  RTC_CHECK(thread_.QueueAPC(&InitializeQueueThread,
                             reinterpret_cast<ULONG_PTR>(&event)));
  event.Wait(rtc::Event::kForever);
}

void TaskQueueWin::Delete() {
  RTC_DCHECK(!IsCurrent());
  while (!::PostThreadMessage(thread_.GetThreadRef(), WM_QUIT, 0, 0)) {
    RTC_CHECK_EQ(ERROR_NOT_ENOUGH_QUOTA, ::GetLastError());
    Sleep(1);
  }
  thread_.Stop();
  ::CloseHandle(in_queue_);
  delete this;
}

void TaskQueueWin::PostTask(std::unique_ptr<QueuedTask> task) {
  rtc::CritScope lock(&pending_lock_);
  pending_.push(std::move(task));
  ::SetEvent(in_queue_);
}

void TaskQueueWin::PostDelayedTask(std::unique_ptr<QueuedTask> task,
                                   uint32_t milliseconds) {
  if (!milliseconds) {
    PostTask(std::move(task));
    return;
  }

  // TODO(tommi): Avoid this allocation.  It is currently here since
  // the timestamp stored in the task info object, is a 64bit timestamp
  // and WPARAM is 32bits in 32bit builds.  Otherwise, we could pass the
  // task pointer and timestamp as LPARAM and WPARAM.
  auto* task_info = new DelayedTaskInfo(milliseconds, std::move(task));
  if (!::PostThreadMessage(thread_.GetThreadRef(), WM_QUEUE_DELAYED_TASK, 0,
                           reinterpret_cast<LPARAM>(task_info))) {
    delete task_info;
  }
}

void TaskQueueWin::RunPendingTasks() {
  while (true) {
    std::unique_ptr<QueuedTask> task;
    {
      rtc::CritScope lock(&pending_lock_);
      if (pending_.empty())
        break;
      task = std::move(pending_.front());
      pending_.pop();
    }

    if (!task->Run())
      task.release();
  }
}

// static
void TaskQueueWin::ThreadMain(void* context) {
  static_cast<TaskQueueWin*>(context)->RunThreadMain();
}

void TaskQueueWin::RunThreadMain() {
  CurrentTaskQueueSetter set_current(this);
  HANDLE handles[2] = {*timer_.event_for_wait(), in_queue_};
  while (true) {
    // Make sure we do an alertable wait as that's required to allow APCs to run
    // (e.g. required for InitializeQueueThread and stopping the thread in
    // PlatformThread).
    DWORD result = ::MsgWaitForMultipleObjectsEx(
        arraysize(handles), handles, INFINITE, QS_ALLEVENTS, MWMO_ALERTABLE);
    RTC_CHECK_NE(WAIT_FAILED, result);
    if (result == (WAIT_OBJECT_0 + 2)) {
      // There are messages in the message queue that need to be handled.
      if (!ProcessQueuedMessages())
        break;
    }

    if (result == WAIT_OBJECT_0 ||
        (!timer_tasks_.empty() &&
         ::WaitForSingleObject(*timer_.event_for_wait(), 0) == WAIT_OBJECT_0)) {
      // The multimedia timer was signaled.
      timer_.Cancel();
      RunDueTasks();
      ScheduleNextTimer();
    }

    if (result == (WAIT_OBJECT_0 + 1)) {
      ::ResetEvent(in_queue_);
      RunPendingTasks();
    }
  }
}

bool TaskQueueWin::ProcessQueuedMessages() {
  MSG msg = {};
  // To protect against overly busy message queues, we limit the time
  // we process tasks to a few milliseconds. If we don't do that, there's
  // a chance that timer tasks won't ever run.
  static const int kMaxTaskProcessingTimeMs = 500;
  auto start = GetTick();
  while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) &&
         msg.message != WM_QUIT) {
    if (!msg.hwnd) {
      switch (msg.message) {
        // TODO(tommi): Stop using this way of queueing tasks.
        case WM_RUN_TASK: {
          QueuedTask* task = reinterpret_cast<QueuedTask*>(msg.lParam);
          if (task->Run())
            delete task;
          break;
        }
        case WM_QUEUE_DELAYED_TASK: {
          std::unique_ptr<DelayedTaskInfo> info(
              reinterpret_cast<DelayedTaskInfo*>(msg.lParam));
          bool need_to_schedule_timers =
              timer_tasks_.empty() ||
              timer_tasks_.top().due_time() > info->due_time();
          timer_tasks_.emplace(std::move(*info.get()));
          if (need_to_schedule_timers) {
            CancelTimers();
            ScheduleNextTimer();
          }
          break;
        }
        case WM_TIMER: {
          RTC_DCHECK_EQ(timer_id_, msg.wParam);
          ::KillTimer(nullptr, msg.wParam);
          timer_id_ = 0;
          RunDueTasks();
          ScheduleNextTimer();
          break;
        }
        default:
          RTC_NOTREACHED();
          break;
      }
    } else {
      ::TranslateMessage(&msg);
      ::DispatchMessage(&msg);
    }

    if (GetTick() > start + kMaxTaskProcessingTimeMs)
      break;
  }
  return msg.message != WM_QUIT;
}

void TaskQueueWin::RunDueTasks() {
  RTC_DCHECK(!timer_tasks_.empty());
  auto now = GetTick();
  do {
    const auto& top = timer_tasks_.top();
    if (top.due_time() > now)
      break;
    top.Run();
    timer_tasks_.pop();
  } while (!timer_tasks_.empty());
}

void TaskQueueWin::ScheduleNextTimer() {
  RTC_DCHECK_EQ(timer_id_, 0);
  if (timer_tasks_.empty())
    return;

  const auto& next_task = timer_tasks_.top();
  int64_t delay_ms = std::max(0ll, next_task.due_time() - GetTick());
  uint32_t milliseconds = rtc::dchecked_cast<uint32_t>(delay_ms);
  if (!timer_.StartOneShotTimer(milliseconds))
    timer_id_ = ::SetTimer(nullptr, 0, milliseconds, nullptr);
}

void TaskQueueWin::CancelTimers() {
  timer_.Cancel();
  if (timer_id_) {
    ::KillTimer(nullptr, timer_id_);
    timer_id_ = 0;
  }
}

class TaskQueueWinFactory : public TaskQueueFactory {
 public:
  std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
      absl::string_view name,
      Priority priority) const override {
    return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
        new TaskQueueWin(name, TaskQueuePriorityToThreadPriority(priority)));
  }
};

}  // namespace

std::unique_ptr<TaskQueueFactory> CreateTaskQueueWinFactory() {
  return std::make_unique<TaskQueueWinFactory>();
}

}  // namespace webrtc
<commit_msg>In TaskQueueWin fix race in canceling MutlimediaTimer<commit_after>/*
 *  Copyright 2016 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/task_queue_win.h"

// clang-format off
// clang formating would change include order.

// Include winsock2.h before including <windows.h> to maintain consistency with
// win32.h. To include win32.h directly, it must be broken out into its own
// build target.
#include <winsock2.h>
#include <windows.h>
#include <sal.h>       // Must come after windows headers.
#include <mmsystem.h>  // Must come after windows headers.
// clang-format on
#include <string.h>

#include <algorithm>
#include <memory>
#include <queue>
#include <utility>

#include "absl/strings/string_view.h"
#include "api/task_queue/queued_task.h"
#include "api/task_queue/task_queue_base.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/critical_section.h"
#include "rtc_base/event.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/platform_thread.h"
#include "rtc_base/time_utils.h"

namespace webrtc {
namespace {
#define WM_RUN_TASK WM_USER + 1
#define WM_QUEUE_DELAYED_TASK WM_USER + 2

void CALLBACK InitializeQueueThread(ULONG_PTR param) {
  MSG msg;
  ::PeekMessage(&msg, nullptr, WM_USER, WM_USER, PM_NOREMOVE);
  rtc::Event* data = reinterpret_cast<rtc::Event*>(param);
  data->Set();
}

rtc::ThreadPriority TaskQueuePriorityToThreadPriority(
    TaskQueueFactory::Priority priority) {
  switch (priority) {
    case TaskQueueFactory::Priority::HIGH:
      return rtc::kRealtimePriority;
    case TaskQueueFactory::Priority::LOW:
      return rtc::kLowPriority;
    case TaskQueueFactory::Priority::NORMAL:
      return rtc::kNormalPriority;
    default:
      RTC_NOTREACHED();
      break;
  }
  return rtc::kNormalPriority;
}

int64_t GetTick() {
  static const UINT kPeriod = 1;
  bool high_res = (timeBeginPeriod(kPeriod) == TIMERR_NOERROR);
  int64_t ret = rtc::TimeMillis();
  if (high_res)
    timeEndPeriod(kPeriod);
  return ret;
}

class DelayedTaskInfo {
 public:
  // Default ctor needed to support priority_queue::pop().
  DelayedTaskInfo() {}
  DelayedTaskInfo(uint32_t milliseconds, std::unique_ptr<QueuedTask> task)
      : due_time_(GetTick() + milliseconds), task_(std::move(task)) {}
  DelayedTaskInfo(DelayedTaskInfo&&) = default;

  // Implement for priority_queue.
  bool operator>(const DelayedTaskInfo& other) const {
    return due_time_ > other.due_time_;
  }

  // Required by priority_queue::pop().
  DelayedTaskInfo& operator=(DelayedTaskInfo&& other) = default;

  // See below for why this method is const.
  void Run() const {
    RTC_DCHECK(due_time_);
    task_->Run() ? task_.reset() : static_cast<void>(task_.release());
  }

  int64_t due_time() const { return due_time_; }

 private:
  int64_t due_time_ = 0;  // Absolute timestamp in milliseconds.

  // |task| needs to be mutable because std::priority_queue::top() returns
  // a const reference and a key in an ordered queue must not be changed.
  // There are two basic workarounds, one using const_cast, which would also
  // make the key (|due_time|), non-const and the other is to make the non-key
  // (|task|), mutable.
  // Because of this, the |task| variable is made private and can only be
  // mutated by calling the |Run()| method.
  mutable std::unique_ptr<QueuedTask> task_;
};

class MultimediaTimer {
 public:
  // Note: We create an event that requires manual reset.
  MultimediaTimer() : event_(::CreateEvent(nullptr, true, false, nullptr)) {}

  ~MultimediaTimer() {
    Cancel();
    ::CloseHandle(event_);
  }

  bool StartOneShotTimer(UINT delay_ms) {
    RTC_DCHECK_EQ(0, timer_id_);
    RTC_DCHECK(event_ != nullptr);
    timer_id_ =
        ::timeSetEvent(delay_ms, 0, reinterpret_cast<LPTIMECALLBACK>(event_), 0,
                       TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
    return timer_id_ != 0;
  }

  void Cancel() {
    if (timer_id_) {
      ::timeKillEvent(timer_id_);
      timer_id_ = 0;
    }
    // Now that timer is killed and not able to set the event, reset the event.
    // Doing it in opposite order is racy because event may be set between
    // event was reset and timer is killed leaving MultimediaTimer in surprising
    // state where both event is set and timer is canceled.
    ::ResetEvent(event_);
  }

  HANDLE* event_for_wait() { return &event_; }

 private:
  HANDLE event_ = nullptr;
  MMRESULT timer_id_ = 0;

  RTC_DISALLOW_COPY_AND_ASSIGN(MultimediaTimer);
};

class TaskQueueWin : public TaskQueueBase {
 public:
  TaskQueueWin(absl::string_view queue_name, rtc::ThreadPriority priority);
  ~TaskQueueWin() override = default;

  void Delete() override;
  void PostTask(std::unique_ptr<QueuedTask> task) override;
  void PostDelayedTask(std::unique_ptr<QueuedTask> task,
                       uint32_t milliseconds) override;

  void RunPendingTasks();

 private:
  static void ThreadMain(void* context);

  class WorkerThread : public rtc::PlatformThread {
   public:
    WorkerThread(rtc::ThreadRunFunction func,
                 void* obj,
                 absl::string_view thread_name,
                 rtc::ThreadPriority priority)
        : PlatformThread(func, obj, thread_name, priority) {}

    bool QueueAPC(PAPCFUNC apc_function, ULONG_PTR data) {
      return rtc::PlatformThread::QueueAPC(apc_function, data);
    }
  };

  void RunThreadMain();
  bool ProcessQueuedMessages();
  void RunDueTasks();
  void ScheduleNextTimer();
  void CancelTimers();

  // Since priority_queue<> by defult orders items in terms of
  // largest->smallest, using std::less<>, and we want smallest->largest,
  // we would like to use std::greater<> here. Alas it's only available in
  // C++14 and later, so we roll our own compare template that that relies on
  // operator<().
  template <typename T>
  struct greater {
    bool operator()(const T& l, const T& r) { return l > r; }
  };

  MultimediaTimer timer_;
  std::priority_queue<DelayedTaskInfo,
                      std::vector<DelayedTaskInfo>,
                      greater<DelayedTaskInfo>>
      timer_tasks_;
  UINT_PTR timer_id_ = 0;
  WorkerThread thread_;
  rtc::CriticalSection pending_lock_;
  std::queue<std::unique_ptr<QueuedTask>> pending_
      RTC_GUARDED_BY(pending_lock_);
  HANDLE in_queue_;
};

TaskQueueWin::TaskQueueWin(absl::string_view queue_name,
                           rtc::ThreadPriority priority)
    : thread_(&TaskQueueWin::ThreadMain, this, queue_name, priority),
      in_queue_(::CreateEvent(nullptr, true, false, nullptr)) {
  RTC_DCHECK(in_queue_);
  thread_.Start();
  rtc::Event event(false, false);
  RTC_CHECK(thread_.QueueAPC(&InitializeQueueThread,
                             reinterpret_cast<ULONG_PTR>(&event)));
  event.Wait(rtc::Event::kForever);
}

void TaskQueueWin::Delete() {
  RTC_DCHECK(!IsCurrent());
  while (!::PostThreadMessage(thread_.GetThreadRef(), WM_QUIT, 0, 0)) {
    RTC_CHECK_EQ(ERROR_NOT_ENOUGH_QUOTA, ::GetLastError());
    Sleep(1);
  }
  thread_.Stop();
  ::CloseHandle(in_queue_);
  delete this;
}

void TaskQueueWin::PostTask(std::unique_ptr<QueuedTask> task) {
  rtc::CritScope lock(&pending_lock_);
  pending_.push(std::move(task));
  ::SetEvent(in_queue_);
}

void TaskQueueWin::PostDelayedTask(std::unique_ptr<QueuedTask> task,
                                   uint32_t milliseconds) {
  if (!milliseconds) {
    PostTask(std::move(task));
    return;
  }

  // TODO(tommi): Avoid this allocation.  It is currently here since
  // the timestamp stored in the task info object, is a 64bit timestamp
  // and WPARAM is 32bits in 32bit builds.  Otherwise, we could pass the
  // task pointer and timestamp as LPARAM and WPARAM.
  auto* task_info = new DelayedTaskInfo(milliseconds, std::move(task));
  if (!::PostThreadMessage(thread_.GetThreadRef(), WM_QUEUE_DELAYED_TASK, 0,
                           reinterpret_cast<LPARAM>(task_info))) {
    delete task_info;
  }
}

void TaskQueueWin::RunPendingTasks() {
  while (true) {
    std::unique_ptr<QueuedTask> task;
    {
      rtc::CritScope lock(&pending_lock_);
      if (pending_.empty())
        break;
      task = std::move(pending_.front());
      pending_.pop();
    }

    if (!task->Run())
      task.release();
  }
}

// static
void TaskQueueWin::ThreadMain(void* context) {
  static_cast<TaskQueueWin*>(context)->RunThreadMain();
}

void TaskQueueWin::RunThreadMain() {
  CurrentTaskQueueSetter set_current(this);
  HANDLE handles[2] = {*timer_.event_for_wait(), in_queue_};
  while (true) {
    // Make sure we do an alertable wait as that's required to allow APCs to run
    // (e.g. required for InitializeQueueThread and stopping the thread in
    // PlatformThread).
    DWORD result = ::MsgWaitForMultipleObjectsEx(
        arraysize(handles), handles, INFINITE, QS_ALLEVENTS, MWMO_ALERTABLE);
    RTC_CHECK_NE(WAIT_FAILED, result);
    if (result == (WAIT_OBJECT_0 + 2)) {
      // There are messages in the message queue that need to be handled.
      if (!ProcessQueuedMessages())
        break;
    }

    if (result == WAIT_OBJECT_0 ||
        (!timer_tasks_.empty() &&
         ::WaitForSingleObject(*timer_.event_for_wait(), 0) == WAIT_OBJECT_0)) {
      // The multimedia timer was signaled.
      timer_.Cancel();
      RunDueTasks();
      ScheduleNextTimer();
    }

    if (result == (WAIT_OBJECT_0 + 1)) {
      ::ResetEvent(in_queue_);
      RunPendingTasks();
    }
  }
}

bool TaskQueueWin::ProcessQueuedMessages() {
  MSG msg = {};
  // To protect against overly busy message queues, we limit the time
  // we process tasks to a few milliseconds. If we don't do that, there's
  // a chance that timer tasks won't ever run.
  static const int kMaxTaskProcessingTimeMs = 500;
  auto start = GetTick();
  while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) &&
         msg.message != WM_QUIT) {
    if (!msg.hwnd) {
      switch (msg.message) {
        // TODO(tommi): Stop using this way of queueing tasks.
        case WM_RUN_TASK: {
          QueuedTask* task = reinterpret_cast<QueuedTask*>(msg.lParam);
          if (task->Run())
            delete task;
          break;
        }
        case WM_QUEUE_DELAYED_TASK: {
          std::unique_ptr<DelayedTaskInfo> info(
              reinterpret_cast<DelayedTaskInfo*>(msg.lParam));
          bool need_to_schedule_timers =
              timer_tasks_.empty() ||
              timer_tasks_.top().due_time() > info->due_time();
          timer_tasks_.emplace(std::move(*info.get()));
          if (need_to_schedule_timers) {
            CancelTimers();
            ScheduleNextTimer();
          }
          break;
        }
        case WM_TIMER: {
          RTC_DCHECK_EQ(timer_id_, msg.wParam);
          ::KillTimer(nullptr, msg.wParam);
          timer_id_ = 0;
          RunDueTasks();
          ScheduleNextTimer();
          break;
        }
        default:
          RTC_NOTREACHED();
          break;
      }
    } else {
      ::TranslateMessage(&msg);
      ::DispatchMessage(&msg);
    }

    if (GetTick() > start + kMaxTaskProcessingTimeMs)
      break;
  }
  return msg.message != WM_QUIT;
}

void TaskQueueWin::RunDueTasks() {
  RTC_DCHECK(!timer_tasks_.empty());
  auto now = GetTick();
  do {
    const auto& top = timer_tasks_.top();
    if (top.due_time() > now)
      break;
    top.Run();
    timer_tasks_.pop();
  } while (!timer_tasks_.empty());
}

void TaskQueueWin::ScheduleNextTimer() {
  RTC_DCHECK_EQ(timer_id_, 0);
  if (timer_tasks_.empty())
    return;

  const auto& next_task = timer_tasks_.top();
  int64_t delay_ms = std::max(0ll, next_task.due_time() - GetTick());
  uint32_t milliseconds = rtc::dchecked_cast<uint32_t>(delay_ms);
  if (!timer_.StartOneShotTimer(milliseconds))
    timer_id_ = ::SetTimer(nullptr, 0, milliseconds, nullptr);
}

void TaskQueueWin::CancelTimers() {
  timer_.Cancel();
  if (timer_id_) {
    ::KillTimer(nullptr, timer_id_);
    timer_id_ = 0;
  }
}

class TaskQueueWinFactory : public TaskQueueFactory {
 public:
  std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
      absl::string_view name,
      Priority priority) const override {
    return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(
        new TaskQueueWin(name, TaskQueuePriorityToThreadPriority(priority)));
  }
};

}  // namespace

std::unique_ptr<TaskQueueFactory> CreateTaskQueueWinFactory() {
  return std::make_unique<TaskQueueWinFactory>();
}

}  // namespace webrtc
<|endoftext|>