<commit_before>/*
 * ipop-tincan
 * Copyright 2015, University of Florida
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
*/

#include "talk/base/json.h"
#include "controlleraccess.h"
#include "tincan_utils.h"

namespace tincan {

static const char kLocalHost[] = "127.0.0.1";
static const char kLocalHost6[] = "::1";
static const int kUdpPort = 5800;
static const int kBufferSize = 1024;
static std::map<std::string, int> rpc_calls;

enum {
  REGISTER_SVC = 1,
  CREATE_LINK = 2,
  SET_LOCAL_IP = 3,
  SET_REMOTE_IP = 4,
  TRIM_LINK = 5,
  SET_CB_ENDPOINT = 6,
  GET_STATE = 7,
  SET_LOGGING = 8,
  SET_TRANSLATION = 9,
  SET_SWITCHMODE = 10,
  SET_TRIMPOLICY = 11,
  ECHO_REQUEST = 12,
  ECHO_REPLY = 13,
  SET_NETWORK_IGNORE_LIST = 14,
};

static void init_map() {
  rpc_calls["register_svc"] = REGISTER_SVC;
  rpc_calls["create_link"] = CREATE_LINK;
  rpc_calls["set_local_ip"] = SET_LOCAL_IP;
  rpc_calls["set_remote_ip"] = SET_REMOTE_IP;
  rpc_calls["trim_link"] = TRIM_LINK;
  rpc_calls["set_cb_endpoint"] = SET_CB_ENDPOINT;
  rpc_calls["get_state"] = GET_STATE;
  rpc_calls["set_logging"] = SET_LOGGING;
  rpc_calls["set_translation"] = SET_TRANSLATION;
  rpc_calls["set_switchmode"] = SET_SWITCHMODE;
  rpc_calls["set_trimpolicy"] = SET_TRIMPOLICY;
  rpc_calls["echo_request"] = ECHO_REQUEST;
  rpc_calls["echo_reply"] = ECHO_REPLY;
  rpc_calls["set_network_ignore_list"] = SET_NETWORK_IGNORE_LIST;
}

ControllerAccess::ControllerAccess(
    TinCanConnectionManager& manager, XmppNetwork& network,
    talk_base::BasicPacketSocketFactory* packet_factory,
    thread_opts_t* opts)
    : manager_(manager),
      network_(network),
      packet_options_(talk_base::DSCP_DEFAULT),
      opts_(opts) {
  signal_thread_ = talk_base::Thread::Current();
  socket_.reset(packet_factory->CreateUdpSocket(
      talk_base::SocketAddress(kLocalHost, kUdpPort), 0, 0));
  socket_->SignalReadPacket.connect(this, &ControllerAccess::HandlePacket);
  socket6_.reset(packet_factory->CreateUdpSocket(
      talk_base::SocketAddress(kLocalHost6, kUdpPort), 0, 0));
  socket6_->SignalReadPacket.connect(this, &ControllerAccess::HandlePacket);
  manager_.set_forward_socket(socket6_.get());
  init_map();
}

void ControllerAccess::ProcessIPPacket(talk_base::AsyncPacketSocket* socket,
    const char* data, size_t len, const talk_base::SocketAddress& addr) {
  ASSERT(signal_thread_->Current());
  manager_.SendToTap(data + kTincanHeaderSize, len - kTincanHeaderSize);
}

void ControllerAccess::SendTo(const char* pv, size_t cb,
                              const talk_base::SocketAddress& addr) {
  ASSERT(signal_thread_->Current());
  talk_base::scoped_ptr<char[]> msg(new char[cb + kTincanHeaderSize]);
  *(msg.get() + kTincanVerOffset) = kIpopVer;
  *(msg.get() + kTincanMsgTypeOffset) = kTincanControl;
  memcpy(msg.get() + kTincanHeaderSize, pv, cb);
  if (addr.family() == AF_INET) {
    socket_->SendTo(msg.get(), cb + kTincanHeaderSize, addr,
                    packet_options_);
  }
  else if (addr.family() == AF_INET6)  {
    socket6_->SendTo(msg.get(), cb + kTincanHeaderSize, addr,
                     packet_options_);
  }
}

void ControllerAccess::SendToPeer(int overlay_id, const std::string& uid,
                                  const std::string& data,
                                  const std::string& type) {
  ASSERT(signal_thread_->Current());
  Json::Value json(Json::objectValue);
  json["uid"] = uid;
  json["data"] = data;
  json["type"] = type;
  std::string msg = json.toStyledString();
  SendTo(msg.c_str(), msg.size(), remote_addr_);
  LOG_TS(INFO) << "uid:" << uid << " data:" << data << " type:" << type;
}

void ControllerAccess::SendState(const std::string& uid, bool get_stats,
                                 const talk_base::SocketAddress& addr) {
  ASSERT(signal_thread_->Current());
  Json::Value state;
  if (uid != "") {
    std::map<std::string, uint32> friends;
    friends[uid] = talk_base::Time();
    state = manager_.GetState(friends, get_stats);
  }
  else {
    state = manager_.GetState(network_.friends(), get_stats);
  }
  Json::Value local_state;
  local_state["_uid"] = manager_.uid();
  local_state["_ip4"] = manager_.ipv4();
  local_state["_ip6"] = manager_.ipv6();
  local_state["_fpr"] = manager_.fingerprint();
  local_state["type"] = "local_state";
  std::ostringstream mac;
  int i;
  for (i=0; i<6; ++i) {
    if (i != 0) mac << ':';
    mac.width(2);
    mac.fill('0');
    mac << std::hex << ((int) *(opts_->mac+i) & 0xff);
  }
  local_state["_mac"] = mac.str();
  std::string msg = local_state.toStyledString();
  SendTo(msg.c_str(), msg.size(), addr);

  for (Json::ValueIterator it = state.begin(); it != state.end(); it++) {
    Json::Value peer = *it;
    peer["type"] = "peer_state";
    msg = peer.toStyledString();
    SendTo(msg.c_str(), msg.size(), addr);
  }
}

void ControllerAccess::HandlePacket(talk_base::AsyncPacketSocket* socket,
    const char* data, size_t len, const talk_base::SocketAddress& addr,
    const talk_base::PacketTime& ptime) {
  ASSERT(signal_thread_->Current());
  if (data[0] != kIpopVer) {
    LOG_TS(LS_ERROR) << "IPOP version mismatch tincan:" << kIpopVer
                     << " controller:" << data[0];
  }
  if (data[1] == kTincanPacket) return ProcessIPPacket(socket, data, len, addr);
  if (data[1] == kICCControl || data[1] == kICCPacket) {
    /* ICC message is received from controller. Remove IPOP version and type
       field and pass to TinCan Connection manager */
    manager_.HandlePacket(0, data+2, len-2, addr);
    return;
  }
  if (data[1] != kTincanControl) {
    LOG_TS(LS_ERROR) << "Unknown message type";
  }
  std::string result;
  std::string message(data, 2, len);
  Json::Reader reader;
  Json::Value root;
  if (!reader.parse(message, root)) {
    result = "{\"error\":\"json parsing failed\"}";
  }
  else {
    LOG_TS(LS_VERBOSE) << "JSONRPC " << message;
  }

  // TODO - input sanitazation for security purposes
  std::string method = root["m"].asString();

  switch (rpc_calls[method]) {
    case REGISTER_SVC: {
        std::string user = root["username"].asString();
        std::string pass = root["password"].asString();
        std::string host = root["host"].asString();
        bool res = network_.Login(user, pass, manager_.uid(), host);
      }
      break;
    case CREATE_LINK: {
        int overlay_id = root["overlay_id"].asInt();
        std::string uid = root["uid"].asString();
        std::string fpr = root["fpr"].asString();
        std::string stun = root["stun"].asString();
        std::string turn = root["turn"].asString();
        std::string turn_user = root["turn_user"].asString();
        std::string turn_pass = root["turn_pass"].asString();
        std::string cas = root["cas"].asString();
        bool sec = root["sec"].asBool();
        bool res = manager_.CreateTransport(uid, fpr, overlay_id, stun, turn,
                                            turn_user, turn_pass, sec);
        if (!cas.empty()) {
          manager_.CreateConnections(uid, cas);
        }
      }
      break;
    case SET_LOCAL_IP: {
        std::string uid = root["uid"].asString();
        std::string ip4 = root["ip4"].asString();
        std::string ip6 = root["ip6"].asString();
        int ip4_mask = root["ip4_mask"].asInt();
        int ip6_mask = root["ip6_mask"].asInt();
        int subnet_mask = root["subnet_mask"].asInt();
        int switchmode = root["switchmode"].asInt();
        manager_.Setup(uid, ip4, ip4_mask, ip6, ip6_mask, subnet_mask,
                       switchmode);
      }
      break;
    case SET_REMOTE_IP: {
        std::string uid = root["uid"].asString();
        std::string ip4 = root["ip4"].asString();
        std::string ip6 = root["ip6"].asString();
        bool res = manager_.AddIPMapping(uid, ip4, ip6);
      }
      break;
    case TRIM_LINK: {
        std::string uid = root["uid"].asString();
        manager_.DestroyTransport(uid);
      }
      break;
    case SET_CB_ENDPOINT: {
        std::string ip = root["ip"].asString();
        int port = root["port"].asInt();
        // sometimes python sends wrong ip address based on platform
        if (ip.compare("::") == 0) {
          remote_addr_ = addr;
        }
        else {
          remote_addr_.SetIP(ip);
          remote_addr_.SetPort(port);
        }
        manager_.set_forward_addr(remote_addr_);
      }
      break;
    case GET_STATE: {
        std::string uid = root["uid"].asString();
        bool get_stats = root["stats"].asBool();
        SendState(uid, get_stats, addr);
      }
      break;
    case SET_LOGGING: {
        int logging = root["logging"].asInt();
        if (logging == 0) {
          talk_base::LogMessage::LogToDebug(talk_base::LS_ERROR + 1);
        }
        else if (logging == 1) {
          talk_base::LogMessage::LogToDebug(talk_base::LS_ERROR);
        }
        else if (logging == 2) {
          talk_base::LogMessage::LogToDebug(talk_base::LS_INFO);
        }
        else if (logging == 3) {
          talk_base::LogMessage::LogToDebug(talk_base::LS_SENSITIVE);
        }
      }
      break;
    case SET_TRANSLATION: {
        int translate = root["translate"].asInt();
        opts_->translate = translate;
      }
      break;
    case SET_SWITCHMODE: {
        int switchmode = root["switchmode"].asInt();
        opts_->switchmode = switchmode;
      }
      break;
    case SET_TRIMPOLICY: {
        bool trim = root["trim_enabled"].asBool();
        manager_.set_trim_connection(trim);
      }
      break;
    case ECHO_REQUEST: {
        std::string msg = root["msg"].asString();
        Json::Value local_state;
        local_state["type"] = "echo_request";
        local_state["msg"] = msg;
        std::string req = local_state.toStyledString();
        SendTo(req.c_str(), req.size(), addr);
      }
      break;
    case ECHO_REPLY: {
      }
      break;
    case SET_NETWORK_IGNORE_LIST: {
      int count = root["network_ignore_list"].size();
      Json::Value network_ignore_list = root["network_ignore_list"];
      if (network_ignore_list.isArray() != 1) {
        LOG_TS(LERROR) << "Unproperrly styled json network_ignore_list";
        break;
      }
      LOG_TS(INFO) << "Listed network device is ignored for TinCan connection"
                   << network_ignore_list.toStyledString();
      std::vector<std::string> ignore_list(count);
      for (int i=0;i<count;i++) {
        ignore_list[i] = network_ignore_list[i].asString();
      }
      manager_.set_network_ignore_list(ignore_list);
      }
      break;
    default: {
        int overlay_id = root["overlay_id"].asInt();
        std::string uid = root["uid"].asString();
        std::string fpr = root["data"].asString();
        network_.SendToPeer(overlay_id, uid, fpr, method);
      }
      break;
  }

  if (result.empty()) return;
  SendTo(result.c_str(), result.size(), addr);
}

}  // namespace tincan

<commit_msg>fix one thread violation<commit_after>/*
 * ipop-tincan
 * Copyright 2015, University of Florida
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
*/

#include "talk/base/json.h"
#include "controlleraccess.h"
#include "tincan_utils.h"

namespace tincan {

static const char kLocalHost[] = "127.0.0.1";
static const char kLocalHost6[] = "::1";
static const int kUdpPort = 5800;
static const int kBufferSize = 1024;
static std::map<std::string, int> rpc_calls;

enum {
  REGISTER_SVC = 1,
  CREATE_LINK = 2,
  SET_LOCAL_IP = 3,
  SET_REMOTE_IP = 4,
  TRIM_LINK = 5,
  SET_CB_ENDPOINT = 6,
  GET_STATE = 7,
  SET_LOGGING = 8,
  SET_TRANSLATION = 9,
  SET_SWITCHMODE = 10,
  SET_TRIMPOLICY = 11,
  ECHO_REQUEST = 12,
  ECHO_REPLY = 13,
  SET_NETWORK_IGNORE_LIST = 14,
};

static void init_map() {
  rpc_calls["register_svc"] = REGISTER_SVC;
  rpc_calls["create_link"] = CREATE_LINK;
  rpc_calls["set_local_ip"] = SET_LOCAL_IP;
  rpc_calls["set_remote_ip"] = SET_REMOTE_IP;
  rpc_calls["trim_link"] = TRIM_LINK;
  rpc_calls["set_cb_endpoint"] = SET_CB_ENDPOINT;
  rpc_calls["get_state"] = GET_STATE;
  rpc_calls["set_logging"] = SET_LOGGING;
  rpc_calls["set_translation"] = SET_TRANSLATION;
  rpc_calls["set_switchmode"] = SET_SWITCHMODE;
  rpc_calls["set_trimpolicy"] = SET_TRIMPOLICY;
  rpc_calls["echo_request"] = ECHO_REQUEST;
  rpc_calls["echo_reply"] = ECHO_REPLY;
  rpc_calls["set_network_ignore_list"] = SET_NETWORK_IGNORE_LIST;
}

ControllerAccess::ControllerAccess(
    TinCanConnectionManager& manager, XmppNetwork& network,
    talk_base::BasicPacketSocketFactory* packet_factory,
    thread_opts_t* opts)
    : manager_(manager),
      network_(network),
      packet_options_(talk_base::DSCP_DEFAULT),
      opts_(opts) {
  signal_thread_ = talk_base::Thread::Current();
  socket_.reset(packet_factory->CreateUdpSocket(
      talk_base::SocketAddress(kLocalHost, kUdpPort), 0, 0));
  socket_->SignalReadPacket.connect(this, &ControllerAccess::HandlePacket);
  socket6_.reset(packet_factory->CreateUdpSocket(
      talk_base::SocketAddress(kLocalHost6, kUdpPort), 0, 0));
  socket6_->SignalReadPacket.connect(this, &ControllerAccess::HandlePacket);
  manager_.set_forward_socket(socket6_.get());
  init_map();
}

void ControllerAccess::ProcessIPPacket(talk_base::AsyncPacketSocket* socket,
    const char* data, size_t len, const talk_base::SocketAddress& addr) {
  ASSERT(signal_thread_->Current());
  manager_.SendToTap(data + kTincanHeaderSize, len - kTincanHeaderSize);
}

void ControllerAccess::SendTo(const char* pv, size_t cb,
                              const talk_base::SocketAddress& addr) {
  ASSERT(signal_thread_->Current());
  talk_base::scoped_ptr<char[]> msg(new char[cb + kTincanHeaderSize]);
  *(msg.get() + kTincanVerOffset) = kIpopVer;
  *(msg.get() + kTincanMsgTypeOffset) = kTincanControl;
  memcpy(msg.get() + kTincanHeaderSize, pv, cb);
  if (addr.family() == AF_INET) {
    socket_->SendTo(msg.get(), cb + kTincanHeaderSize, addr,
                    packet_options_);
  }
  else if (addr.family() == AF_INET6)  {
    socket6_->SendTo(msg.get(), cb + kTincanHeaderSize, addr,
                     packet_options_);
  }
}

void ControllerAccess::SendToPeer(int overlay_id, const std::string& uid,
                                  const std::string& data,
                                  const std::string& type) {
  ASSERT(signal_thread_->Current());
  Json::Value json(Json::objectValue);
  json["uid"] = uid;
  json["data"] = data;
  json["type"] = type;
  std::string msg = json.toStyledString();
  SendTo(msg.c_str(), msg.size(), remote_addr_);
  LOG_TS(INFO) << "uid:" << uid << " data:" << data << " type:" << type;
}

void ControllerAccess::SendState(const std::string& uid, bool get_stats,
                                 const talk_base::SocketAddress& addr) {
  ASSERT(signal_thread_->Current());
  Json::Value state;
  if (uid != "") {
    std::map<std::string, uint32> friends;
    friends[uid] = talk_base::Time();
    state = manager_.GetState(friends, get_stats);
  }
  else {
    state = manager_.GetState(network_.friends(), get_stats);
  }
  Json::Value local_state;
  local_state["_uid"] = manager_.uid();
  local_state["_ip4"] = manager_.ipv4();
  local_state["_ip6"] = manager_.ipv6();
  local_state["_fpr"] = manager_.fingerprint();
  local_state["type"] = "local_state";
  std::ostringstream mac;
  int i;
  for (i=0; i<6; ++i) {
    if (i != 0) mac << ':';
    mac.width(2);
    mac.fill('0');
    mac << std::hex << ((int) *(opts_->mac+i) & 0xff);
  }
  local_state["_mac"] = mac.str();
  std::string msg = local_state.toStyledString();
  SendTo(msg.c_str(), msg.size(), addr);

  for (Json::ValueIterator it = state.begin(); it != state.end(); it++) {
    Json::Value peer = *it;
    peer["type"] = "peer_state";
    msg = peer.toStyledString();
    SendTo(msg.c_str(), msg.size(), addr);
  }
}

void ControllerAccess::HandlePacket(talk_base::AsyncPacketSocket* socket,
    const char* data, size_t len, const talk_base::SocketAddress& addr,
    const talk_base::PacketTime& ptime) {
  ASSERT(signal_thread_->Current());
  if (data[0] != kIpopVer) {
    LOG_TS(LS_ERROR) << "IPOP version mismatch tincan:" << kIpopVer
                     << " controller:" << data[0];
  }
  if (data[1] == kTincanPacket) return ProcessIPPacket(socket, data, len, addr);
  if (data[1] == kICCControl || data[1] == kICCPacket) {
    /* ICC message is received from controller. Remove IPOP version and type
       field and pass to TinCan Connection manager */
    manager_.DoPacketSend(data+2, len-2);
    return;
  }
  if (data[1] != kTincanControl) {
    LOG_TS(LS_ERROR) << "Unknown message type";
  }
  std::string result;
  std::string message(data, 2, len);
  Json::Reader reader;
  Json::Value root;
  if (!reader.parse(message, root)) {
    result = "{\"error\":\"json parsing failed\"}";
  }
  else {
    LOG_TS(LS_VERBOSE) << "JSONRPC " << message;
  }

  // TODO - input sanitazation for security purposes
  std::string method = root["m"].asString();

  switch (rpc_calls[method]) {
    case REGISTER_SVC: {
        std::string user = root["username"].asString();
        std::string pass = root["password"].asString();
        std::string host = root["host"].asString();
        bool res = network_.Login(user, pass, manager_.uid(), host);
      }
      break;
    case CREATE_LINK: {
        int overlay_id = root["overlay_id"].asInt();
        std::string uid = root["uid"].asString();
        std::string fpr = root["fpr"].asString();
        std::string stun = root["stun"].asString();
        std::string turn = root["turn"].asString();
        std::string turn_user = root["turn_user"].asString();
        std::string turn_pass = root["turn_pass"].asString();
        std::string cas = root["cas"].asString();
        bool sec = root["sec"].asBool();
        bool res = manager_.CreateTransport(uid, fpr, overlay_id, stun, turn,
                                            turn_user, turn_pass, sec);
        if (!cas.empty()) {
          manager_.CreateConnections(uid, cas);
        }
      }
      break;
    case SET_LOCAL_IP: {
        std::string uid = root["uid"].asString();
        std::string ip4 = root["ip4"].asString();
        std::string ip6 = root["ip6"].asString();
        int ip4_mask = root["ip4_mask"].asInt();
        int ip6_mask = root["ip6_mask"].asInt();
        int subnet_mask = root["subnet_mask"].asInt();
        int switchmode = root["switchmode"].asInt();
        manager_.Setup(uid, ip4, ip4_mask, ip6, ip6_mask, subnet_mask,
                       switchmode);
      }
      break;
    case SET_REMOTE_IP: {
        std::string uid = root["uid"].asString();
        std::string ip4 = root["ip4"].asString();
        std::string ip6 = root["ip6"].asString();
        bool res = manager_.AddIPMapping(uid, ip4, ip6);
      }
      break;
    case TRIM_LINK: {
        std::string uid = root["uid"].asString();
        manager_.DestroyTransport(uid);
      }
      break;
    case SET_CB_ENDPOINT: {
        std::string ip = root["ip"].asString();
        int port = root["port"].asInt();
        // sometimes python sends wrong ip address based on platform
        if (ip.compare("::") == 0) {
          remote_addr_ = addr;
        }
        else {
          remote_addr_.SetIP(ip);
          remote_addr_.SetPort(port);
        }
        manager_.set_forward_addr(remote_addr_);
      }
      break;
    case GET_STATE: {
        std::string uid = root["uid"].asString();
        bool get_stats = root["stats"].asBool();
        SendState(uid, get_stats, addr);
      }
      break;
    case SET_LOGGING: {
        int logging = root["logging"].asInt();
        if (logging == 0) {
          talk_base::LogMessage::LogToDebug(talk_base::LS_ERROR + 1);
        }
        else if (logging == 1) {
          talk_base::LogMessage::LogToDebug(talk_base::LS_ERROR);
        }
        else if (logging == 2) {
          talk_base::LogMessage::LogToDebug(talk_base::LS_INFO);
        }
        else if (logging == 3) {
          talk_base::LogMessage::LogToDebug(talk_base::LS_SENSITIVE);
        }
      }
      break;
    case SET_TRANSLATION: {
        int translate = root["translate"].asInt();
        opts_->translate = translate;
      }
      break;
    case SET_SWITCHMODE: {
        int switchmode = root["switchmode"].asInt();
        opts_->switchmode = switchmode;
      }
      break;
    case SET_TRIMPOLICY: {
        bool trim = root["trim_enabled"].asBool();
        manager_.set_trim_connection(trim);
      }
      break;
    case ECHO_REQUEST: {
        std::string msg = root["msg"].asString();
        Json::Value local_state;
        local_state["type"] = "echo_request";
        local_state["msg"] = msg;
        std::string req = local_state.toStyledString();
        SendTo(req.c_str(), req.size(), addr);
      }
      break;
    case ECHO_REPLY: {
      }
      break;
    case SET_NETWORK_IGNORE_LIST: {
      int count = root["network_ignore_list"].size();
      Json::Value network_ignore_list = root["network_ignore_list"];
      if (network_ignore_list.isArray() != 1) {
        LOG_TS(LERROR) << "Unproperrly styled json network_ignore_list";
        break;
      }
      LOG_TS(INFO) << "Listed network device is ignored for TinCan connection"
                   << network_ignore_list.toStyledString();
      std::vector<std::string> ignore_list(count);
      for (int i=0;i<count;i++) {
        ignore_list[i] = network_ignore_list[i].asString();
      }
      manager_.set_network_ignore_list(ignore_list);
      }
      break;
    default: {
        int overlay_id = root["overlay_id"].asInt();
        std::string uid = root["uid"].asString();
        std::string fpr = root["data"].asString();
        network_.SendToPeer(overlay_id, uid, fpr, method);
      }
      break;
  }

  if (result.empty()) return;
  SendTo(result.c_str(), result.size(), addr);
}

}  // namespace tincan

<|endoftext|>


<commit_before>/* Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2017, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * 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 Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#ifndef NUPIC_UTIL_SLIDING_WINDOW_HPP
#define NUPIC_UTIL_SLIDING_WINDOW_HPP

#include <vector>
#include <algorithm>

#include <nupic/types/Types.hpp>
#include <nupic/utils/Log.hpp>

namespace nupic {
  namespace util {

    template<class T>
    class SlidingWindow {
      public:
        SlidingWindow(UInt maxCapacity);
        SlidingWindow(UInt maxCapacity, std::vector<T> initialData);
        const UInt maxCapacity;
        const T NEUTRAL_VALUE = 0.0;
        UInt size() const;
        /** append new value to the end of the buffer and handle the "overflows"-may pop the first element if full.
         :return addition(+) neutral value (that is 0) when size()< maxCapacity; when full - return the value of the dropped element
        */
        T append(T newValue);
        /**
        * :return unordered content (data ) of this sl. window; call getLinearizedData() if you need them oredered from oldest->newest
        * This direct access method is fast.
        */
        const std::vector<T>& getData() const;

        /** linearize method for the internal buffer; this is slower than the pure getData() but ensures that the data are ordered (oldest at the
         * beginning, newest at the end of the vector
         * This handles case of |5,6;1,2,3,4| => |1,2,3,4,5,6|
         * :return new linearized vector
        */
        std::vector<T> getLinearizedData() const;

        bool operator==(const SlidingWindow& r2) const;
        bool operator!=(const SlidingWindow& r2) const;
        T& operator[](UInt index);
        const T& operator[](UInt index) const;

      private:
        std::vector<T> buffer_;
        UInt idxNext_;
};
}} //end ns

/// IMPLEMENTATION
#include <cmath>

using namespace std;
using namespace nupic;
using namespace nupic::util;

template<class T>
SlidingWindow<T>::SlidingWindow(UInt maxCapacity) :
  maxCapacity(maxCapacity) {
  NTA_CHECK(maxCapacity > 0);
  buffer_.reserve(maxCapacity);
  idxNext_ = 0;
}

template<class T>
SlidingWindow<T>::SlidingWindow(UInt maxCapacity, vector<T> initialData)  :
  SlidingWindow(maxCapacity) {
  buffer_.insert(begin(buffer_), end(initialData) - std::min(initialData.size(), (size_t)maxCapacity), end(initialData));
  idxNext_ = initialData.size();
}

template<class T>
UInt SlidingWindow<T>::size() const {
  NTA_ASSERT(buffer_.size() <= maxCapacity);
  return buffer_.size();
}

template<class T>
T SlidingWindow<T>::append(T newValue) {
  Real old = NEUTRAL_VALUE;

  if(buffer_.size() < maxCapacity) {
    buffer_.emplace_back(newValue);
  } else {
    old = buffer_[idxNext_];  //FIXME this IF is here only because size() wouldn't work w/o it or similar hack
    buffer_[idxNext_] = newValue;
  }
  idxNext_ = ++idxNext_ % maxCapacity;
  return old;
}

template<class T>
const vector<T>& SlidingWindow<T>::getData() const {
  return buffer_;
}

template<class T>
vector<T> SlidingWindow<T>::getLinearizedData() const {
  vector<T> lin;
  lin.reserve(buffer_.size());

  if(size() ==0) return lin; //empty buffer
  lin.insert(begin(lin), begin(buffer_) + idxNext_, end(buffer_)); //insert the "older" part at the beginning
  if(idxNext_ != 0) { //need to append second (unlinear) part
    lin.insert(end(lin), begin(buffer_), begin(buffer_) + idxNext_); //append the "newer" part to the end of the constructed vect
  }
  return lin;
}

template<class T>
bool SlidingWindow<T>::operator==(const SlidingWindow& r2) const //FIXME review the ==, on my machine it randomly passes/fails the test!
{
  bool sameData = this->getData()== r2.getData();
  return ((this->size() == r2.size()) && (this->maxCapacity == r2.maxCapacity) && sameData);
}

template<class T>
bool SlidingWindow<T>::operator!=(const SlidingWindow& r2) const
{
  return !operator==(r2);
}

template<class T>
T& SlidingWindow<T>::operator[](UInt index) {
  NTA_ASSERT(index <= size());
  return &buffer_[index];
}

template<class T>
const T& SlidingWindow<T>::operator[](UInt index) const {
  return this->operator[](index); //call the overloaded operator[] above
}

#endif //header
<commit_msg>SlidingWindow rev2: simplify ifs<commit_after>/* Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2017, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * 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 Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#ifndef NUPIC_UTIL_SLIDING_WINDOW_HPP
#define NUPIC_UTIL_SLIDING_WINDOW_HPP

#include <vector>
#include <algorithm>

#include <nupic/types/Types.hpp>
#include <nupic/utils/Log.hpp>

namespace nupic {
  namespace util {

    template<class T>
    class SlidingWindow {
      public:
        SlidingWindow(UInt maxCapacity);
        SlidingWindow(UInt maxCapacity, std::vector<T> initialData);
        const UInt maxCapacity;
        const T NEUTRAL_VALUE = 0.0;
        UInt size() const;
        /** append new value to the end of the buffer and handle the "overflows"-may pop the first element if full.
         :return addition(+) neutral value (that is 0) when size()< maxCapacity; when full - return the value of the dropped element
        */
        T append(T newValue);
        /**
        * :return unordered content (data ) of this sl. window; call getLinearizedData() if you need them oredered from oldest->newest
        * This direct access method is fast.
        */
        const std::vector<T>& getData() const;

        /** linearize method for the internal buffer; this is slower than the pure getData() but ensures that the data are ordered (oldest at the
         * beginning, newest at the end of the vector
         * This handles case of |5,6;1,2,3,4| => |1,2,3,4,5,6|
         * :return new linearized vector
        */
        std::vector<T> getLinearizedData() const;

        bool operator==(const SlidingWindow& r2) const;
        bool operator!=(const SlidingWindow& r2) const;
        T& operator[](UInt index);
        const T& operator[](UInt index) const;

      private:
        std::vector<T> buffer_;
        UInt idxNext_;
};
}} //end ns

/// IMPLEMENTATION
#include <cmath>

using namespace std;
using namespace nupic;
using namespace nupic::util;

template<class T>
SlidingWindow<T>::SlidingWindow(UInt maxCapacity) :
  maxCapacity(maxCapacity) {
  NTA_CHECK(maxCapacity > 0);
  buffer_.reserve(maxCapacity);
  idxNext_ = 0;
}

template<class T>
SlidingWindow<T>::SlidingWindow(UInt maxCapacity, vector<T> initialData)  :
  SlidingWindow(maxCapacity) {
  buffer_.insert(begin(buffer_), end(initialData) - std::min(initialData.size(), (size_t)maxCapacity), end(initialData));
  idxNext_ = initialData.size();
}

template<class T>
UInt SlidingWindow<T>::size() const {
  NTA_ASSERT(buffer_.size() <= maxCapacity);
  return buffer_.size();
}

template<class T>
T SlidingWindow<T>::append(T newValue) {
  Real old = NEUTRAL_VALUE;

  if(buffer_.size() < maxCapacity) {
    buffer_.emplace_back(newValue);
  } else {
    old = buffer_[idxNext_];  //FIXME this IF is here only because size() wouldn't work w/o it or similar hack
    buffer_[idxNext_] = newValue;
  }
  idxNext_ = ++idxNext_ % maxCapacity;
  return old;
}

template<class T>
const vector<T>& SlidingWindow<T>::getData() const {
  return buffer_;
}

template<class T>
vector<T> SlidingWindow<T>::getLinearizedData() const {
  vector<T> lin;
  lin.reserve(buffer_.size());

  lin.insert(begin(lin), begin(buffer_) + idxNext_, end(buffer_)); //insert the "older" part at the beginning
  lin.insert(end(lin), begin(buffer_), begin(buffer_) + idxNext_); //append the "newer" part to the end of the constructed vect
 return lin;
}

template<class T>
bool SlidingWindow<T>::operator==(const SlidingWindow& r2) const //FIXME review the ==, on my machine it randomly passes/fails the test!
{
  bool sameData = this->getData()== r2.getData();
  return ((this->size() == r2.size()) && (this->maxCapacity == r2.maxCapacity) && sameData);
}

template<class T>
bool SlidingWindow<T>::operator!=(const SlidingWindow& r2) const
{
  return !operator==(r2);
}

template<class T>
T& SlidingWindow<T>::operator[](UInt index) {
  NTA_ASSERT(index <= size());
  return &buffer_[index];
}

template<class T>
const T& SlidingWindow<T>::operator[](UInt index) const {
  return this->operator[](index); //call the overloaded operator[] above
}

#endif //header
<|endoftext|>


<commit_before>#include <list>
#include <algorithm>
#include "rtmidi/RtMidi.h"
#include "core.hpp"
#include "MidiIO.hpp"

/*
 * MIDIToCVInterface converts midi note on/off events, velocity , channel aftertouch, pitch wheel and mod weel to
 * CV
 */
struct MIDICCToCVInterface : MidiIO, Module {
	enum ParamIds {
		NUM_PARAMS
	};
	enum InputIds {
		NUM_INPUTS
	};
	enum OutputIds {
		NUM_OUTPUTS = 16
	};

	int cc[NUM_OUTPUTS];
	int ccNum[NUM_OUTPUTS];
	bool ccSync[NUM_OUTPUTS];
	bool ccNumInited[NUM_OUTPUTS];
	bool onFocus[NUM_OUTPUTS];
	float lights[NUM_OUTPUTS];

	MIDICCToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
		for (int i = 0; i < NUM_OUTPUTS; i++) {
			cc[i] = 0;
			ccNum[i] = i;
			onFocus[i] = false;
			ccSync[i]  = true;
		}
	}

	~MIDICCToCVInterface() {

	}

	void step();

	void processMidi(std::vector<unsigned char> msg);

	void resetMidi();

	json_t *toJson() {
		json_t *rootJ = json_object();
		addBaseJson(rootJ);
		for (int i = 0; i < NUM_OUTPUTS; i++) {
			json_object_set_new(rootJ, ("ccNum" + std::to_string(i)).c_str(), json_integer(ccNum[i]));
			json_object_set_new(rootJ, ("ccVal" + std::to_string(i)).c_str(), json_integer(cc[i]));
		}
		return rootJ;
	}

	void fromJson(json_t *rootJ) {
		baseFromJson(rootJ);
		for (int i = 0; i < NUM_OUTPUTS; i++) {
			json_t *ccNumJ = json_object_get(rootJ, ("ccNum" + std::to_string(i)).c_str());
			if (ccNumJ) {
				ccNum[i] = json_integer_value(ccNumJ);
				ccNumInited[i] = true;
			}

			json_t *ccValJ = json_object_get(rootJ, ("ccNum" + std::to_string(i)).c_str());
			if (ccValJ) {
				cc[i] = json_integer_value(ccValJ);
				ccSync[i] = false;
			}

		}
	}

	void reset() {
		resetMidi();
	}

};

void MIDICCToCVInterface::step() {
	if (isPortOpen()) {
		std::vector<unsigned char> message;

		// midiIn->getMessage returns empty vector if there are no messages in the queue
		getMessage(&message);
		while (message.size() > 0) {
			processMidi(message);
			getMessage(&message);
		}
	}

	for (int i = 0; i < NUM_OUTPUTS; i++) {

		lights[i] = ccSync[i] ? 0.0 : 1.0;

		outputs[i].value = cc[i] / 127.0 * 10.0;
	}
}

void MIDICCToCVInterface::resetMidi() {
	for (int i = 0; i < NUM_OUTPUTS; i++) {
		cc[i] = 0;
	}
};

void MIDICCToCVInterface::processMidi(std::vector<unsigned char> msg) {
	int channel = msg[0] & 0xf;
	int status = (msg[0] >> 4) & 0xf;
	int data1 = msg[1];
	int data2 = msg[2];

	//fprintf(stderr, "channel %d status %d data1 %d data2 %d\n", channel, status, data1,data2);

	// Filter channels
	if (this->channel >= 0 && this->channel != channel)
		return;

	if (status == 0xb) {
		for (int i = 0; i < NUM_OUTPUTS; i++) {
			if (onFocus[i]) {
				if (ccNum[i] != data1) {
					ccSync[i] = false;
				}
				this->ccNum[i] = data1;
			}
		}
		for (int i = 0; i < NUM_OUTPUTS; i++) {

			if (data1 == ccNum[i]) {
				if (!ccSync[i]) {
					ccSync[i] = (cc[i] <= data2+1 && cc[i] >= data2-1) ;
					break;
				}

				this->cc[i] = data2;
			}
		}
	}
}

struct CCTextField : TextField {
	void onTextChange();

	void draw(NVGcontext *vg);

	void onMouseDownOpaque(int button);

	void onMouseUpOpaque(int button);

	void onMouseLeave();

	int *ccNum;
	bool *inited;
	bool *onFocus;
	bool *ccSync;
};

void CCTextField::draw(NVGcontext *vg) {
	/* This is necessary, since the save
	 * file is loaded after constructing the widget*/
	if (*inited) {
		*inited = false;
		text = std::to_string(*ccNum);
	}

	if (*onFocus) {
		text = std::to_string(*ccNum);
	}

	TextField::draw(vg);
}

void CCTextField::onMouseUpOpaque(int button) {
	if (button == 1) {
		*onFocus = false;
	}

}

void CCTextField::onMouseDownOpaque(int button) {
	if (button == 1) {
		*onFocus = true;
	}
}

void CCTextField::onMouseLeave() {
	*onFocus = false;
}

void CCTextField::onTextChange() {
	if (text.size() > 0) {
		try {
			if (*ccNum != std::stoi(text)) {
				*ccSync = false;
			}
			*ccNum = std::stoi(text);
			// Only allow valid cc numbers
			if (*ccNum < 0 || *ccNum > 127 || text.size() > 3) {
				text = "";
				begin = end = 0;
				*ccNum = -1;
			}
		} catch (...) {
			text = "";
			begin = end = 0;
			*ccNum = -1;
		}
	};
}

MIDICCToCVWidget::MIDICCToCVWidget() {
	MIDICCToCVInterface *module = new MIDICCToCVInterface();
	setModule(module);
	box.size = Vec(16 * 15, 380);

	{
		Panel *panel = new LightPanel();
		panel->box.size = box.size;
		addChild(panel);
	}

	float margin = 5;
	float labelHeight = 15;
	float yPos = margin;

	addChild(createScrew<ScrewSilver>(Vec(15, 0)));
	addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 0)));
	addChild(createScrew<ScrewSilver>(Vec(15, 365)));
	addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 365)));
	{
		Label *label = new Label();
		label->box.pos = Vec(box.size.x - margin - 11 * 15, margin);
		label->text = "MIDI CC to CV";
		addChild(label);
		yPos = labelHeight * 2;
	}

	{
		Label *label = new Label();
		label->box.pos = Vec(margin, yPos);
		label->text = "MIDI Interface";
		addChild(label);

		MidiChoice *midiChoice = new MidiChoice();
		midiChoice->midiModule = dynamic_cast<MidiIO *>(module);
		midiChoice->box.pos = Vec((box.size.x - 10) / 2 + margin, yPos);
		midiChoice->box.size.x = (box.size.x / 2.0) - margin;
		addChild(midiChoice);
		yPos += midiChoice->box.size.y + margin;
	}

	{
		Label *label = new Label();
		label->box.pos = Vec(margin, yPos);
		label->text = "Channel";
		addChild(label);

		ChannelChoice *channelChoice = new ChannelChoice();
		channelChoice->midiModule = dynamic_cast<MidiIO *>(module);
		channelChoice->box.pos = Vec((box.size.x - 10) / 2 + margin, yPos);
		channelChoice->box.size.x = (box.size.x / 2.0) - margin;
		addChild(channelChoice);
		yPos += channelChoice->box.size.y + margin * 3;
	}

	for (int i = 0; i < MIDICCToCVInterface::NUM_OUTPUTS; i++) {
		CCTextField *ccNumChoice = new CCTextField();
		ccNumChoice->ccNum = &module->ccNum[i];
		ccNumChoice->inited = &module->ccNumInited[i];
		ccNumChoice->onFocus = &module->onFocus[i];
		ccNumChoice->ccSync = &module->ccSync[i];
		ccNumChoice->text = std::to_string(module->ccNum[i]);
		ccNumChoice->box.pos = Vec(11 + (i % 4) * (63), yPos);
		ccNumChoice->box.size.x = 29;

		addChild(ccNumChoice);

		yPos += labelHeight + margin;
		addOutput(createOutput<PJ3410Port>(Vec((i % 4) * (63) + 10, yPos + 5), module, i));
		addChild(createValueLight<SmallLight<RedValueLight>>(Vec((i % 4) * (63) + 32, yPos + 5), &module->lights[i]));

		if ((i + 1) % 4 == 0) {
			yPos += 47 + margin;
		} else {
			yPos -= labelHeight + margin;
		}
	}
}

void MIDICCToCVWidget::step() {

	ModuleWidget::step();
}
<commit_msg>fixes<commit_after>#include <list>
#include <algorithm>
#include "rtmidi/RtMidi.h"
#include "core.hpp"
#include "MidiIO.hpp"

/*
 * MIDIToCVInterface converts midi note on/off events, velocity , channel aftertouch, pitch wheel and mod weel to
 * CV
 */
struct MIDICCToCVInterface : MidiIO, Module {
	enum ParamIds {
		NUM_PARAMS
	};
	enum InputIds {
		NUM_INPUTS
	};
	enum OutputIds {
		NUM_OUTPUTS = 16
	};

	int cc[NUM_OUTPUTS];
	int ccNum[NUM_OUTPUTS];
	bool ccSync[NUM_OUTPUTS];
	bool ccNumInited[NUM_OUTPUTS];
	bool onFocus[NUM_OUTPUTS];
	float lights[NUM_OUTPUTS];

	MIDICCToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
		for (int i = 0; i < NUM_OUTPUTS; i++) {
			cc[i] = 0;
			ccNum[i] = i;
			onFocus[i] = false;
			ccSync[i]  = true;
		}
	}

	~MIDICCToCVInterface() {

	}

	void step();

	void processMidi(std::vector<unsigned char> msg);

	void resetMidi();

	json_t *toJson() {
		json_t *rootJ = json_object();
		addBaseJson(rootJ);
		for (int i = 0; i < NUM_OUTPUTS; i++) {
			json_object_set_new(rootJ, ("ccNum" + std::to_string(i)).c_str(), json_integer(ccNum[i]));
			if(outputs[i].active){
				json_object_set_new(rootJ, ("ccVal" + std::to_string(i)).c_str(), json_integer(cc[i]));
			}
		}
		return rootJ;
	}

	void fromJson(json_t *rootJ) {
		baseFromJson(rootJ);
		for (int i = 0; i < NUM_OUTPUTS; i++) {
			json_t *ccNumJ = json_object_get(rootJ, ("ccNum" + std::to_string(i)).c_str());
			if (ccNumJ) {
				ccNum[i] = json_integer_value(ccNumJ);
				ccNumInited[i] = true;
			}

			json_t *ccValJ = json_object_get(rootJ, ("ccVal" + std::to_string(i)).c_str());
			if (ccValJ) {
				cc[i] = json_integer_value(ccValJ);
				ccSync[i] = false;
			}

		}
	}

	void reset() {
		resetMidi();
	}

};

void MIDICCToCVInterface::step() {
	if (isPortOpen()) {
		std::vector<unsigned char> message;

		// midiIn->getMessage returns empty vector if there are no messages in the queue
		getMessage(&message);
		while (message.size() > 0) {
			processMidi(message);
			getMessage(&message);
		}
	}

	for (int i = 0; i < NUM_OUTPUTS; i++) {

		lights[i] = ccSync[i] ? 0.0 : 1.0;

		outputs[i].value = cc[i] / 127.0 * 10.0;
	}
}

void MIDICCToCVInterface::resetMidi() {
	for (int i = 0; i < NUM_OUTPUTS; i++) {
		cc[i] = 0;
	}
};

void MIDICCToCVInterface::processMidi(std::vector<unsigned char> msg) {
	int channel = msg[0] & 0xf;
	int status = (msg[0] >> 4) & 0xf;
	int data1 = msg[1];
	int data2 = msg[2];

	//fprintf(stderr, "channel %d status %d data1 %d data2 %d\n", channel, status, data1,data2);

	// Filter channels
	if (this->channel >= 0 && this->channel != channel)
		return;

	if (status == 0xb) {
		for (int i = 0; i < NUM_OUTPUTS; i++) {
			if (onFocus[i]) {
				if (ccNum[i] != data1) {
					ccSync[i] = false;
				}
				this->ccNum[i] = data1;
			}
		}
		for (int i = 0; i < NUM_OUTPUTS; i++) {

			if (data1 == ccNum[i]) {
				if (!ccSync[i]) {
					ccSync[i] = (cc[i] <= data2+1 && cc[i] >= data2-1) ;
					break;
				}

				this->cc[i] = data2;
			}
		}
	}
}

struct CCTextField : TextField {
	void onTextChange();

	void draw(NVGcontext *vg);

	void onMouseDownOpaque(int button);

	void onMouseUpOpaque(int button);

	void onMouseLeave();

	int *ccNum;
	bool *inited;
	bool *onFocus;
	bool *ccSync;
};

void CCTextField::draw(NVGcontext *vg) {
	/* This is necessary, since the save
	 * file is loaded after constructing the widget*/
	if (*inited) {
		*inited = false;
		text = std::to_string(*ccNum);
	}

	if (*onFocus) {
		text = std::to_string(*ccNum);
	}

	TextField::draw(vg);
}

void CCTextField::onMouseUpOpaque(int button) {
	if (button == 1) {
		*onFocus = false;
	}

}

void CCTextField::onMouseDownOpaque(int button) {
	if (button == 1) {
		*onFocus = true;
	}
}

void CCTextField::onMouseLeave() {
	*onFocus = false;
}

void CCTextField::onTextChange() {
	if (text.size() > 0) {
		try {
			*ccNum = std::stoi(text);
			// Only allow valid cc numbers
			if (*ccNum < 0 || *ccNum > 127 || text.size() > 3) {
				text = "";
				begin = end = 0;
				*ccNum = -1;
				return;
			}

			if (!*inited && *ccNum != std::stoi(text)) {
				*ccSync = false;
			}

		} catch (...) {
			text = "";
			begin = end = 0;
			*ccNum = -1;
		}
	};
}

MIDICCToCVWidget::MIDICCToCVWidget() {
	MIDICCToCVInterface *module = new MIDICCToCVInterface();
	setModule(module);
	box.size = Vec(16 * 15, 380);

	{
		Panel *panel = new LightPanel();
		panel->box.size = box.size;
		addChild(panel);
	}

	float margin = 5;
	float labelHeight = 15;
	float yPos = margin;

	addChild(createScrew<ScrewSilver>(Vec(15, 0)));
	addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 0)));
	addChild(createScrew<ScrewSilver>(Vec(15, 365)));
	addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 365)));
	{
		Label *label = new Label();
		label->box.pos = Vec(box.size.x - margin - 11 * 15, margin);
		label->text = "MIDI CC to CV";
		addChild(label);
		yPos = labelHeight * 2;
	}

	{
		Label *label = new Label();
		label->box.pos = Vec(margin, yPos);
		label->text = "MIDI Interface";
		addChild(label);

		MidiChoice *midiChoice = new MidiChoice();
		midiChoice->midiModule = dynamic_cast<MidiIO *>(module);
		midiChoice->box.pos = Vec((box.size.x - 10) / 2 + margin, yPos);
		midiChoice->box.size.x = (box.size.x / 2.0) - margin;
		addChild(midiChoice);
		yPos += midiChoice->box.size.y + margin;
	}

	{
		Label *label = new Label();
		label->box.pos = Vec(margin, yPos);
		label->text = "Channel";
		addChild(label);

		ChannelChoice *channelChoice = new ChannelChoice();
		channelChoice->midiModule = dynamic_cast<MidiIO *>(module);
		channelChoice->box.pos = Vec((box.size.x - 10) / 2 + margin, yPos);
		channelChoice->box.size.x = (box.size.x / 2.0) - margin;
		addChild(channelChoice);
		yPos += channelChoice->box.size.y + margin * 3;
	}

	for (int i = 0; i < MIDICCToCVInterface::NUM_OUTPUTS; i++) {
		CCTextField *ccNumChoice = new CCTextField();
		ccNumChoice->ccNum = &module->ccNum[i];
		ccNumChoice->inited = &module->ccNumInited[i];
		ccNumChoice->onFocus = &module->onFocus[i];
		ccNumChoice->ccSync = &module->ccSync[i];
		ccNumChoice->text = std::to_string(module->ccNum[i]);
		ccNumChoice->box.pos = Vec(11 + (i % 4) * (63), yPos);
		ccNumChoice->box.size.x = 29;

		addChild(ccNumChoice);

		yPos += labelHeight + margin;
		addOutput(createOutput<PJ3410Port>(Vec((i % 4) * (63) + 10, yPos + 5), module, i));
		addChild(createValueLight<SmallLight<RedValueLight>>(Vec((i % 4) * (63) + 32, yPos + 5), &module->lights[i]));

		if ((i + 1) % 4 == 0) {
			yPos += 47 + margin;
		} else {
			yPos -= labelHeight + margin;
		}
	}
}

void MIDICCToCVWidget::step() {

	ModuleWidget::step();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2011 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkAdvancedTypefaceMetrics.h"
#include "SkFontDescriptor.h"
#include "SkFontHost.h"
#include "SkFontStream.h"
#include "SkStream.h"
#include "SkTypeface.h"

SK_DEFINE_INST_COUNT(SkTypeface)

//#define TRACE_LIFECYCLE

#ifdef TRACE_LIFECYCLE
    static int32_t gTypefaceCounter;
#endif

SkTypeface::SkTypeface(Style style, SkFontID fontID, bool isFixedPitch)
    : fUniqueID(fontID), fStyle(style), fIsFixedPitch(isFixedPitch) {
#ifdef TRACE_LIFECYCLE
    SkDebugf("SkTypeface: create  %p fontID %d total %d\n",
             this, fontID, ++gTypefaceCounter);
#endif
}

SkTypeface::~SkTypeface() {
#ifdef TRACE_LIFECYCLE
    SkDebugf("SkTypeface: destroy %p fontID %d total %d\n",
             this, fUniqueID, --gTypefaceCounter);
#endif
}

///////////////////////////////////////////////////////////////////////////////

SkTypeface* SkTypeface::GetDefaultTypeface() {
    // we keep a reference to this guy for all time, since if we return its
    // fontID, the font cache may later on ask to resolve that back into a
    // typeface object.
    static SkTypeface* gDefaultTypeface;

    if (NULL == gDefaultTypeface) {
        gDefaultTypeface =
        SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
    }
    return gDefaultTypeface;
}

SkTypeface* SkTypeface::RefDefault() {
    return SkRef(GetDefaultTypeface());
}

uint32_t SkTypeface::UniqueID(const SkTypeface* face) {
    if (NULL == face) {
        face = GetDefaultTypeface();
    }
    return face->uniqueID();
}

bool SkTypeface::Equal(const SkTypeface* facea, const SkTypeface* faceb) {
    return SkTypeface::UniqueID(facea) == SkTypeface::UniqueID(faceb);
}

///////////////////////////////////////////////////////////////////////////////

SkTypeface* SkTypeface::CreateFromName(const char name[], Style style) {
    return SkFontHost::CreateTypeface(NULL, name, style);
}

SkTypeface* SkTypeface::CreateFromTypeface(const SkTypeface* family, Style s) {
    if (family && family->style() == s) {
        family->ref();
        return const_cast<SkTypeface*>(family);
    }
    return SkFontHost::CreateTypeface(family, NULL, s);
}

SkTypeface* SkTypeface::CreateFromStream(SkStream* stream) {
    return SkFontHost::CreateTypefaceFromStream(stream);
}

SkTypeface* SkTypeface::CreateFromFile(const char path[]) {
    return SkFontHost::CreateTypefaceFromFile(path);
}

///////////////////////////////////////////////////////////////////////////////

void SkTypeface::serialize(SkWStream* wstream) const {
    bool isLocal = false;
    SkFontDescriptor desc(this->style());
    this->onGetFontDescriptor(&desc, &isLocal);

    desc.serialize(wstream);
    if (isLocal) {
        int ttcIndex;   // TODO: write this to the stream?
        SkAutoTUnref<SkStream> rstream(this->openStream(&ttcIndex));
        if (rstream.get()) {
            size_t length = rstream->getLength();
            wstream->writePackedUInt(length);
            wstream->writeStream(rstream, length);
        } else {
            wstream->writePackedUInt(0);
        }
    } else {
        wstream->writePackedUInt(0);
    }
}

SkTypeface* SkTypeface::Deserialize(SkStream* stream) {
    SkFontDescriptor desc(stream);
    size_t length = stream->readPackedUInt();
    if (length > 0) {
        void* addr = sk_malloc_flags(length, 0);
        if (addr) {
            SkAutoTUnref<SkStream> localStream(SkNEW_ARGS(SkMemoryStream,
                                                        (addr, length, false)));
            if (stream->read(addr, length) == length) {
                return SkTypeface::CreateFromStream(localStream.get());
            } else {
                // Failed to read the full font data, so fall through and try to create from name.
                // If this is because of EOF, all subsequent reads from the stream will be EOF.
                // If this is because of a stream error, the stream is in an error state,
                // do not attempt to skip any remaining bytes.
            }
        } else {
            // failed to allocate, so just skip and create-from-name
            stream->skip(length);
        }
    }

    return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
}

///////////////////////////////////////////////////////////////////////////////

int SkTypeface::countTables() const {
    return this->onGetTableTags(NULL);
}

int SkTypeface::getTableTags(SkFontTableTag tags[]) const {
    return this->onGetTableTags(tags);
}

size_t SkTypeface::getTableSize(SkFontTableTag tag) const {
    return this->onGetTableData(tag, 0, ~0U, NULL);
}

size_t SkTypeface::getTableData(SkFontTableTag tag, size_t offset, size_t length,
                                void* data) const {
    return this->onGetTableData(tag, offset, length, data);
}

SkStream* SkTypeface::openStream(int* ttcIndex) const {
    int ttcIndexStorage;
    if (NULL == ttcIndex) {
        // So our subclasses don't need to check for null param
        ttcIndex = &ttcIndexStorage;
    }
    return this->onOpenStream(ttcIndex);
}

int SkTypeface::getUnitsPerEm() const {
    // should we try to cache this in the base-class?
    return this->onGetUPEM();
}

SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics(
                                SkAdvancedTypefaceMetrics::PerGlyphInfo info,
                                const uint32_t* glyphIDs,
                                uint32_t glyphIDsCount) const {
    return this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

int SkTypeface::onGetUPEM() const {
    int upem = 0;

    SkAdvancedTypefaceMetrics* metrics;
    metrics = this->getAdvancedTypefaceMetrics(
                             SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo,
                             NULL, 0);
    if (metrics) {
        upem = metrics->fEmSize;
        metrics->unref();
    }
    return upem;
}

int SkTypeface::onGetTableTags(SkFontTableTag tags[]) const {
    int ttcIndex;
    SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
    return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
}

size_t SkTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
                                  size_t length, void* data) const {
    int ttcIndex;
    SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
    return stream.get()
        ? SkFontStream::GetTableData(stream, ttcIndex, tag, offset, length, data)
        : 0;
}
<commit_msg>Fix memory leak in SkTypeface.cpp<commit_after>/*
 * Copyright 2011 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkAdvancedTypefaceMetrics.h"
#include "SkFontDescriptor.h"
#include "SkFontHost.h"
#include "SkFontStream.h"
#include "SkStream.h"
#include "SkTypeface.h"

SK_DEFINE_INST_COUNT(SkTypeface)

//#define TRACE_LIFECYCLE

#ifdef TRACE_LIFECYCLE
    static int32_t gTypefaceCounter;
#endif

SkTypeface::SkTypeface(Style style, SkFontID fontID, bool isFixedPitch)
    : fUniqueID(fontID), fStyle(style), fIsFixedPitch(isFixedPitch) {
#ifdef TRACE_LIFECYCLE
    SkDebugf("SkTypeface: create  %p fontID %d total %d\n",
             this, fontID, ++gTypefaceCounter);
#endif
}

SkTypeface::~SkTypeface() {
#ifdef TRACE_LIFECYCLE
    SkDebugf("SkTypeface: destroy %p fontID %d total %d\n",
             this, fUniqueID, --gTypefaceCounter);
#endif
}

///////////////////////////////////////////////////////////////////////////////

SkTypeface* SkTypeface::GetDefaultTypeface() {
    // we keep a reference to this guy for all time, since if we return its
    // fontID, the font cache may later on ask to resolve that back into a
    // typeface object.
    static SkTypeface* gDefaultTypeface;

    if (NULL == gDefaultTypeface) {
        gDefaultTypeface =
        SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
    }
    return gDefaultTypeface;
}

SkTypeface* SkTypeface::RefDefault() {
    return SkRef(GetDefaultTypeface());
}

uint32_t SkTypeface::UniqueID(const SkTypeface* face) {
    if (NULL == face) {
        face = GetDefaultTypeface();
    }
    return face->uniqueID();
}

bool SkTypeface::Equal(const SkTypeface* facea, const SkTypeface* faceb) {
    return SkTypeface::UniqueID(facea) == SkTypeface::UniqueID(faceb);
}

///////////////////////////////////////////////////////////////////////////////

SkTypeface* SkTypeface::CreateFromName(const char name[], Style style) {
    return SkFontHost::CreateTypeface(NULL, name, style);
}

SkTypeface* SkTypeface::CreateFromTypeface(const SkTypeface* family, Style s) {
    if (family && family->style() == s) {
        family->ref();
        return const_cast<SkTypeface*>(family);
    }
    return SkFontHost::CreateTypeface(family, NULL, s);
}

SkTypeface* SkTypeface::CreateFromStream(SkStream* stream) {
    return SkFontHost::CreateTypefaceFromStream(stream);
}

SkTypeface* SkTypeface::CreateFromFile(const char path[]) {
    return SkFontHost::CreateTypefaceFromFile(path);
}

///////////////////////////////////////////////////////////////////////////////

void SkTypeface::serialize(SkWStream* wstream) const {
    bool isLocal = false;
    SkFontDescriptor desc(this->style());
    this->onGetFontDescriptor(&desc, &isLocal);

    desc.serialize(wstream);
    if (isLocal) {
        int ttcIndex;   // TODO: write this to the stream?
        SkAutoTUnref<SkStream> rstream(this->openStream(&ttcIndex));
        if (rstream.get()) {
            size_t length = rstream->getLength();
            wstream->writePackedUInt(length);
            wstream->writeStream(rstream, length);
        } else {
            wstream->writePackedUInt(0);
        }
    } else {
        wstream->writePackedUInt(0);
    }
}

SkTypeface* SkTypeface::Deserialize(SkStream* stream) {
    SkFontDescriptor desc(stream);
    size_t length = stream->readPackedUInt();
    if (length > 0) {
        void* addr = sk_malloc_flags(length, 0);
        if (addr) {
            SkAutoTUnref<SkMemoryStream> localStream(SkNEW(SkMemoryStream));
            localStream->setMemoryOwned(addr, length);

            if (stream->read(addr, length) == length) {
                return SkTypeface::CreateFromStream(localStream.get());
            } else {
                // Failed to read the full font data, so fall through and try to create from name.
                // If this is because of EOF, all subsequent reads from the stream will be EOF.
                // If this is because of a stream error, the stream is in an error state,
                // do not attempt to skip any remaining bytes.
            }
        } else {
            // failed to allocate, so just skip and create-from-name
            stream->skip(length);
        }
    }

    return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
}

///////////////////////////////////////////////////////////////////////////////

int SkTypeface::countTables() const {
    return this->onGetTableTags(NULL);
}

int SkTypeface::getTableTags(SkFontTableTag tags[]) const {
    return this->onGetTableTags(tags);
}

size_t SkTypeface::getTableSize(SkFontTableTag tag) const {
    return this->onGetTableData(tag, 0, ~0U, NULL);
}

size_t SkTypeface::getTableData(SkFontTableTag tag, size_t offset, size_t length,
                                void* data) const {
    return this->onGetTableData(tag, offset, length, data);
}

SkStream* SkTypeface::openStream(int* ttcIndex) const {
    int ttcIndexStorage;
    if (NULL == ttcIndex) {
        // So our subclasses don't need to check for null param
        ttcIndex = &ttcIndexStorage;
    }
    return this->onOpenStream(ttcIndex);
}

int SkTypeface::getUnitsPerEm() const {
    // should we try to cache this in the base-class?
    return this->onGetUPEM();
}

SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics(
                                SkAdvancedTypefaceMetrics::PerGlyphInfo info,
                                const uint32_t* glyphIDs,
                                uint32_t glyphIDsCount) const {
    return this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

int SkTypeface::onGetUPEM() const {
    int upem = 0;

    SkAdvancedTypefaceMetrics* metrics;
    metrics = this->getAdvancedTypefaceMetrics(
                             SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo,
                             NULL, 0);
    if (metrics) {
        upem = metrics->fEmSize;
        metrics->unref();
    }
    return upem;
}

int SkTypeface::onGetTableTags(SkFontTableTag tags[]) const {
    int ttcIndex;
    SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
    return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
}

size_t SkTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
                                  size_t length, void* data) const {
    int ttcIndex;
    SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
    return stream.get()
        ? SkFontStream::GetTableData(stream, ttcIndex, tag, offset, length, data)
        : 0;
}
<|endoftext|>


<commit_before>
/*
 * Copyright 2012 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkUtilsArm.h"

#if SK_ARM_NEON_IS_DYNAMIC

#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

// Set USE_ANDROID_NDK_CPU_FEATURES to use the Android NDK's
// cpu-features helper library to detect NEON at runtime. See
// http://crbug.com/164154 to see why this is needed in Chromium
// for Android.
#if !defined(USE_ANDROID_NDK_CPU_FEATURES)
#  if defined(SK_BUILD_FOR_ANDROID)
#    define USE_ANDROID_NDK_CPU_FEATURES 1
#  else
#    define USE_ANDROID_NDK_CPU_FEATURES 0
#  endif
#endif

#if USE_ANDROID_NDK_CPU_FEATURES
#  include <cpu-features.h>
#endif

// Set NEON_DEBUG to 1 to allow debugging of the CPU features probing.
// For now, we always set it for SK_DEBUG builds.
#ifdef SK_DEBUG
#  define NEON_DEBUG  1
#else
#  define NEON_DEBUG 0
#endif

#if NEON_DEBUG
#  ifdef SK_BUILD_FOR_ANDROID
     // used to declare PROP_VALUE_MAX and __system_property_get()
#    include <sys/system_properties.h>
#  endif
#endif

// A function used to determine at runtime if the target CPU supports
// the ARM NEON instruction set. This implementation is Linux-specific.
static bool sk_cpu_arm_check_neon(void) {
    bool result = false;

#if NEON_DEBUG
    // Allow forcing the mode through the environment during debugging.
#  ifdef SK_BUILD_FOR_ANDROID
    // On Android, we use a system property
#   define PROP_NAME  "debug.skia.arm_neon_mode"
    char prop[PROP_VALUE_MAX];
    if (__system_property_get(PROP_NAME, prop) > 0) {
#  else
#   define PROP_NAME   "SKIA_ARM_NEON_MODE"
    // On ARM Linux, we use an environment variable
    const char* prop = getenv(PROP_NAME);
    if (prop != NULL) {
#  endif
        SkDebugf("%s: %s", PROP_NAME, prop);
        if (!strcmp(prop, "1")) {
            SkDebugf("Forcing ARM Neon mode to full!\n");
            return true;
        }
        if (!strcmp(prop, "0")) {
            SkDebugf("Disabling ARM NEON mode\n");
            return false;
        }
    }
    SkDebugf("Running dynamic CPU feature detection\n");
#endif

#if USE_ANDROID_NDK_CPU_FEATURES

  result = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;

#else  // USE_ANDROID_NDK_CPU_FEATURES

    // There is no user-accessible CPUID instruction on ARM that we can use.
    // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature.
    // For example, here's a typical output (Nexus S running ICS 4.0.3):
    /*
    Processor       : ARMv7 Processor rev 2 (v7l)
    BogoMIPS        : 994.65
    Features        : swp half thumb fastmult vfp edsp thumbee neon vfpv3
    CPU implementer : 0x41
    CPU architecture: 7
    CPU variant     : 0x2
    CPU part        : 0xc08
    CPU revision    : 2

    Hardware        : herring
    Revision        : 000b
    Serial          : 3833c77d6dc000ec
    */
    char   buffer[4096];

    // If we fail any of the following, assume we don't have NEON instructions
    // This allows us to return immediately in case of error.
    result = false;

    do {
        // open /proc/cpuinfo
        int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY));
        if (fd < 0) {
            SkDebugf("Could not open /proc/cpuinfo: %s\n", strerror(errno));
            break;
        }

        // Read the file. To simplify our search, we're going to place two
        // sentinel '\n' characters: one at the start of the buffer, and one at
        // the end. This means we reserve the first and last buffer bytes.
        buffer[0] = '\n';
        int size = TEMP_FAILURE_RETRY(read(fd, buffer+1, sizeof(buffer)-2));
        close(fd);

        if (size < 0) {  // should not happen
            SkDebugf("Could not read /proc/cpuinfo: %s\n", strerror(errno));
            break;
        }

        SkDebugf("START /proc/cpuinfo:\n%.*s\nEND /proc/cpuinfo\n",
                 size, buffer+1);

        // Compute buffer limit, and place final sentinel
        char* buffer_end = buffer + 1 + size;
        buffer_end[0] = '\n';

        // Now, find a line that starts with "Features", i.e. look for
        // '\nFeatures ' in our buffer.
        const char features[] = "\nFeatures\t";
        const size_t features_len = sizeof(features)-1;

        char*  line = (char*) memmem(buffer, buffer_end - buffer,
                                     features, features_len);
        if (line == NULL) {  // Weird, no Features line, bad kernel?
            SkDebugf("Could not find a line starting with 'Features'"
              "in /proc/cpuinfo ?\n");
            break;
        }

        line += features_len;  // Skip the "\nFeatures\t" prefix

        // Find the end of the current line
        char* line_end = (char*) memchr(line, '\n', buffer_end - line);
        if (line_end == NULL)
            line_end = buffer_end;

        // Now find an instance of 'neon' in the flags list. We want to
        // ensure it's only 'neon' and not something fancy like 'noneon'
        // so check that it follows a space.
        const char neon[] = " neon";
        const size_t neon_len = sizeof(neon)-1;
        const char* flag = (const char*) memmem(line, line_end - line,
                                                neon, neon_len);
        if (flag == NULL)
            break;

        // Ensure it is followed by a space or a newline.
        if (flag[neon_len] != ' ' && flag[neon_len] != '\n')
            break;

        // Fine, we support Arm NEON !
        result = true;

    } while (0);

#endif  // USE_ANDROID_NDK_CPU_FEATURES

    if (result) {
        SkDebugf("Device supports ARM NEON instructions!\n");
    } else {
        SkDebugf("Device does NOT support ARM NEON instructions!\n");
    }
    return result;
}

static pthread_once_t  sOnce;
static bool            sHasArmNeon;

// called through pthread_once()
void sk_cpu_arm_probe_features(void) {
    sHasArmNeon = sk_cpu_arm_check_neon();
}

bool sk_cpu_arm_has_neon(void) {
    pthread_once(&sOnce, sk_cpu_arm_probe_features);
    return sHasArmNeon;
}

#endif // SK_ARM_NEON_IS_DYNAMIC
<commit_msg>Always use cpu-features library on android.<commit_after>
/*
 * Copyright 2012 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkUtilsArm.h"

#if SK_ARM_NEON_IS_DYNAMIC

#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

#if SK_BUILD_FOR_ANDROID
#  include <cpu-features.h>
#endif

// A function used to determine at runtime if the target CPU supports
// the ARM NEON instruction set. This implementation is Linux-specific.
static bool sk_cpu_arm_check_neon(void) {
    // If we fail any of the following, assume we don't have NEON instructions
    // This allows us to return immediately in case of error.
    bool result = false;

// Use the Android NDK's cpu-features helper library to detect NEON at runtime.
// See http://crbug.com/164154 to see why this is needed in Chromium for Android.
#ifdef SK_BUILD_FOR_ANDROID

  result = (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;

#else  // SK_BUILD_FOR_ANDROID

    // There is no user-accessible CPUID instruction on ARM that we can use.
    // Instead, we must parse /proc/cpuinfo and look for the 'neon' feature.
    // For example, here's a typical output (Nexus S running ICS 4.0.3):
    /*
    Processor       : ARMv7 Processor rev 2 (v7l)
    BogoMIPS        : 994.65
    Features        : swp half thumb fastmult vfp edsp thumbee neon vfpv3
    CPU implementer : 0x41
    CPU architecture: 7
    CPU variant     : 0x2
    CPU part        : 0xc08
    CPU revision    : 2

    Hardware        : herring
    Revision        : 000b
    Serial          : 3833c77d6dc000ec
    */
    char   buffer[4096];

    do {
        // open /proc/cpuinfo
        int fd = TEMP_FAILURE_RETRY(open("/proc/cpuinfo", O_RDONLY));
        if (fd < 0) {
            SkDebugf("Could not open /proc/cpuinfo: %s\n", strerror(errno));
            break;
        }

        // Read the file. To simplify our search, we're going to place two
        // sentinel '\n' characters: one at the start of the buffer, and one at
        // the end. This means we reserve the first and last buffer bytes.
        buffer[0] = '\n';
        int size = TEMP_FAILURE_RETRY(read(fd, buffer+1, sizeof(buffer)-2));
        close(fd);

        if (size < 0) {  // should not happen
            SkDebugf("Could not read /proc/cpuinfo: %s\n", strerror(errno));
            break;
        }

        SkDebugf("START /proc/cpuinfo:\n%.*s\nEND /proc/cpuinfo\n",
                 size, buffer+1);

        // Compute buffer limit, and place final sentinel
        char* buffer_end = buffer + 1 + size;
        buffer_end[0] = '\n';

        // Now, find a line that starts with "Features", i.e. look for
        // '\nFeatures ' in our buffer.
        const char features[] = "\nFeatures\t";
        const size_t features_len = sizeof(features)-1;

        char*  line = (char*) memmem(buffer, buffer_end - buffer,
                                     features, features_len);
        if (line == NULL) {  // Weird, no Features line, bad kernel?
            SkDebugf("Could not find a line starting with 'Features'"
              "in /proc/cpuinfo ?\n");
            break;
        }

        line += features_len;  // Skip the "\nFeatures\t" prefix

        // Find the end of the current line
        char* line_end = (char*) memchr(line, '\n', buffer_end - line);
        if (line_end == NULL)
            line_end = buffer_end;

        // Now find an instance of 'neon' in the flags list. We want to
        // ensure it's only 'neon' and not something fancy like 'noneon'
        // so check that it follows a space.
        const char neon[] = " neon";
        const size_t neon_len = sizeof(neon)-1;
        const char* flag = (const char*) memmem(line, line_end - line,
                                                neon, neon_len);
        if (flag == NULL)
            break;

        // Ensure it is followed by a space or a newline.
        if (flag[neon_len] != ' ' && flag[neon_len] != '\n')
            break;

        // Fine, we support Arm NEON !
        result = true;

    } while (0);

#endif  // SK_BUILD_FOR_ANDROID

    if (result) {
        SkDEBUGF(("Device supports ARM NEON instructions!\n"));
    } else {
        SkDEBUGF(("Device does NOT support ARM NEON instructions!\n"));
    }
    return result;
}

static pthread_once_t  sOnce;
static bool            sHasArmNeon;

// called through pthread_once()
void sk_cpu_arm_probe_features(void) {
    sHasArmNeon = sk_cpu_arm_check_neon();
}

bool sk_cpu_arm_has_neon(void) {
    pthread_once(&sOnce, sk_cpu_arm_probe_features);
    return sHasArmNeon;
}

#endif // SK_ARM_NEON_IS_DYNAMIC
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////////
// Original authors: SangGi Do(sanggido@unist.ac.kr), Mingyu Woo(mwoo@eng.ucsd.edu)
//          (respective Ph.D. advisors: Seokhyeong Kang, Andrew B. Kahng)
// Rewrite by James Cherry, Parallax Software, Inc.

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

#include <iostream>
#include <limits>
#include <iomanip>
#include <cmath>
#include "opendp/Opendp.h"

namespace opendp {

using std::cout;
using std::endl;
using std::make_pair;
using std::max;
using std::min;
using std::ofstream;
using std::pair;
using std::to_string;
using std::vector;

using odb::adsRect;

bool Opendp::checkPlacement(bool verbose) {
  bool fail = false;
  fail |= row_check(verbose);
  fail |= site_check(verbose);
  fail |= power_line_check(verbose);
  fail |= placed_check(verbose);
  fail |= overlap_check(verbose);
  return fail;
}

bool Opendp::row_check(bool verbose) {
  bool fail = false;
  int count = 0;
  for(Cell& cell : cells_) {
    if(!isFixed(&cell)) {
      if(cell.y_ % row_height_ != 0) {
	if (verbose)
	  cout << "row_check fail => " << cell.name()
	       << " y : " << cell.y_ << endl;
	fail = true;
	count++;
      }
    }
  }

  if(fail)
    cout << "row check ==> FAIL (" << count << ")" << endl;
  else
    cout << "row check ==> PASS " << endl;

  return fail;
}

bool Opendp::site_check(bool verbose) {
  bool fail = false;
  int count = 0;
  for(Cell& cell : cells_) {
    if(!isFixed(&cell)) {
      if(cell.x_ % site_width_ != 0) {
	if (verbose)
	  cout << "site check fail ==> " << cell.name()
	       << " x_ : " << cell.x_ << endl;
	fail = true;
	count++;
      }
    }
  }
  if(fail)
    cout << "site check ==> FAIL (" << count << ")" << endl;
  else
    cout << "site check ==> PASS " << endl;
  return fail;
}

bool Opendp::power_line_check(bool verbose) {
  bool fail = false;
  int count = 0;
  for(Cell& cell : cells_) {
    if(!isFixed(&cell)
       // Magic number alert
       // Shouldn't this be odd test instead of 1 or 3? -cherry
       && !(cell.height_ == row_height_ || cell.height_ == row_height_ * 3)
       // should removed later
       && cell.inGroup()) {
      int y_size = gridHeight(&cell);
      int grid_y = gridY(&cell);
      power top_power = topPower(&cell);
      if(y_size % 2 == 0) {
	if(top_power == rowTopPower(grid_y)) {
	  cout << "power check fail ( even height ) ==> "
	      << cell.name() << endl;
	  fail = true;
	  count++;
	}
      }
      else {
	if(top_power == rowTopPower(grid_y)) {
	  if(cell.db_inst_->getOrient() != dbOrientType::R0) {
	    cout << "power check fail ( Should be N ) ==> "
		<< cell.name() << endl;
	    fail = true;
	    count++;
	  }
	}
	else {
	  if(cell.db_inst_->getOrient() != dbOrientType::MX) {
	    cout << "power_check fail ( Should be FS ) ==> "
		<< cell.name() << endl;
	    fail = true;
	    count++;
	  }
	}
      }
    }
  }

  if(fail)
    cout << "power check ==> FAIL (" << count << ")" << endl;
  else
    cout << "power check ==> PASS " << endl;
  return fail;
}

bool Opendp::placed_check(bool verbose) {
  bool fail = false;
  int count = 0;
  for(Cell& cell : cells_) {
    if(!cell.is_placed_) {
      if (verbose)
	cout << "placed check fail ==> " << cell.name() << endl;
      fail = true;
      count++;
    }
  }

  if(fail)
    cout << "placed_check ==> FAIL (" << count << ")" << endl;
  else
    cout << "placed_check ==>> PASS " << endl;

  return fail;
}

bool Opendp::overlap_check(bool verbose) {
  bool fail = false;
  Grid *grid = makeGrid();

  for(Cell& cell : cells_) {
    int grid_x = gridPaddedX(&cell);
    int grid_y = gridY(&cell);

    int x_ur = gridPaddedEndX(&cell);
    int y_ur = gridEndY(&cell);

    // Fixed cells can be outside DIEAREA.
    if (!isFixed(&cell)
	&& (grid_x < 0
	    || grid_y < 0
	    || x_ur > row_site_count_
	    || y_ur > row_count_)) {
      printf("Cell %s %sis outside the core boundary.\n",
	     cell.name(),
	     isPadded(&cell) ? "with padding " : "");
      fail = true;
    }

    grid_x = max(0, grid_x);
    grid_y = max(0, grid_y);
    x_ur = min(x_ur, row_site_count_);
    y_ur = min(y_ur, row_count_);

    for(int j = grid_y; j < y_ur; j++) {
      for(int k = grid_x; k < x_ur; k++) {
        if(grid[j][k].cell == nullptr) {
          grid[j][k].cell = &cell;
          grid[j][k].util = 1.0;
        }
        else {
	  if (verbose)
	    cout << "overlap_check ==> FAIL ( cell " << cell.name()
		 << " overlaps " << grid[j][k].cell->name() << " ) "
		 << " ( " << (k * site_width_ + core_.xMin()) << ", "
		 << (j * row_height_ + core_.yMin()) << " )" << endl;
	  fail = true;
        }
      }
    }
  }
  deleteGrid(grid);

  if(fail)
    cout << "overlap_check ==> FAIL " << endl;
  else
    cout << "overlap_check ==> PASS " << endl;
  return fail;
}

}  // namespace opendp
<commit_msg>opendp padding does not apply to fixed insts<commit_after>/////////////////////////////////////////////////////////////////////////////
// Original authors: SangGi Do(sanggido@unist.ac.kr), Mingyu Woo(mwoo@eng.ucsd.edu)
//          (respective Ph.D. advisors: Seokhyeong Kang, Andrew B. Kahng)
// Rewrite by James Cherry, Parallax Software, Inc.

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

#include <iostream>
#include <limits>
#include <iomanip>
#include <cmath>
#include "opendp/Opendp.h"

namespace opendp {

using std::cout;
using std::endl;
using std::make_pair;
using std::max;
using std::min;
using std::ofstream;
using std::pair;
using std::to_string;
using std::vector;

using odb::adsRect;

bool Opendp::checkPlacement(bool verbose) {
  bool fail = false;
  fail |= row_check(verbose);
  fail |= site_check(verbose);
  fail |= power_line_check(verbose);
  fail |= placed_check(verbose);
  fail |= overlap_check(verbose);
  return fail;
}

bool Opendp::row_check(bool verbose) {
  bool fail = false;
  int count = 0;
  for(Cell& cell : cells_) {
    if(!isFixed(&cell)) {
      if(cell.y_ % row_height_ != 0) {
	if (verbose)
	  cout << "row_check fail => " << cell.name()
	       << " y : " << cell.y_ << endl;
	fail = true;
	count++;
      }
    }
  }

  if(fail)
    cout << "row check ==> FAIL (" << count << ")" << endl;
  else
    cout << "row check ==> PASS " << endl;

  return fail;
}

bool Opendp::site_check(bool verbose) {
  bool fail = false;
  int count = 0;
  for(Cell& cell : cells_) {
    if(!isFixed(&cell)) {
      if(cell.x_ % site_width_ != 0) {
	if (verbose)
	  cout << "site check fail ==> " << cell.name()
	       << " x_ : " << cell.x_ << endl;
	fail = true;
	count++;
      }
    }
  }
  if(fail)
    cout << "site check ==> FAIL (" << count << ")" << endl;
  else
    cout << "site check ==> PASS " << endl;
  return fail;
}

bool Opendp::power_line_check(bool verbose) {
  bool fail = false;
  int count = 0;
  for(Cell& cell : cells_) {
    if(!isFixed(&cell)
       // Magic number alert
       // Shouldn't this be odd test instead of 1 or 3? -cherry
       && !(cell.height_ == row_height_ || cell.height_ == row_height_ * 3)
       // should removed later
       && cell.inGroup()) {
      int y_size = gridHeight(&cell);
      int grid_y = gridY(&cell);
      power top_power = topPower(&cell);
      if(y_size % 2 == 0) {
	if(top_power == rowTopPower(grid_y)) {
	  cout << "power check fail ( even height ) ==> "
	      << cell.name() << endl;
	  fail = true;
	  count++;
	}
      }
      else {
	if(top_power == rowTopPower(grid_y)) {
	  if(cell.db_inst_->getOrient() != dbOrientType::R0) {
	    cout << "power check fail ( Should be N ) ==> "
		<< cell.name() << endl;
	    fail = true;
	    count++;
	  }
	}
	else {
	  if(cell.db_inst_->getOrient() != dbOrientType::MX) {
	    cout << "power_check fail ( Should be FS ) ==> "
		<< cell.name() << endl;
	    fail = true;
	    count++;
	  }
	}
      }
    }
  }

  if(fail)
    cout << "power check ==> FAIL (" << count << ")" << endl;
  else
    cout << "power check ==> PASS " << endl;
  return fail;
}

bool Opendp::placed_check(bool verbose) {
  bool fail = false;
  int count = 0;
  for(Cell& cell : cells_) {
    if(!cell.is_placed_) {
      if (verbose)
	cout << "placed check fail ==> " << cell.name() << endl;
      fail = true;
      count++;
    }
  }

  if(fail)
    cout << "placed_check ==> FAIL (" << count << ")" << endl;
  else
    cout << "placed_check ==>> PASS " << endl;

  return fail;
}

bool Opendp::overlap_check(bool verbose) {
  bool fail = false;
  Grid *grid = makeGrid();

  for(Cell& cell : cells_) {
    int grid_x, x_ur;
    int grid_y = gridY(&cell);
    int y_ur = gridEndY(&cell);

    // Fixed cells can be outside DIEAREA.
    if (isFixed(&cell)) {
      grid_x = gridX(&cell);
      x_ur = gridEndX(&cell);
    }
    else {
      grid_x = gridPaddedX(&cell);
      x_ur = gridPaddedEndX(&cell);
      if (grid_x < 0
	  || grid_y < 0
	  || x_ur > row_site_count_
	  || y_ur > row_count_) {
	printf("Cell %s %sis outside the core boundary.\n",
	       cell.name(),
	       isPadded(&cell) ? "with padding " : "");
	fail = true;
      }
    }

    grid_x = max(0, grid_x);
    grid_y = max(0, grid_y);
    x_ur = min(x_ur, row_site_count_);
    y_ur = min(y_ur, row_count_);

    for(int j = grid_y; j < y_ur; j++) {
      for(int k = grid_x; k < x_ur; k++) {
        if(grid[j][k].cell == nullptr) {
          grid[j][k].cell = &cell;
          grid[j][k].util = 1.0;
        }
        else {
	  if (verbose)
	    cout << "overlap_check ==> FAIL ( cell " << cell.name()
		 << " overlaps " << grid[j][k].cell->name() << " ) "
		 << " ( " << (k * site_width_ + core_.xMin()) << ", "
		 << (j * row_height_ + core_.yMin()) << " )" << endl;
	  fail = true;
        }
      }
    }
  }
  deleteGrid(grid);

  if(fail)
    cout << "overlap_check ==> FAIL " << endl;
  else
    cout << "overlap_check ==> PASS " << endl;
  return fail;
}

}  // namespace opendp
<|endoftext|>