<commit_before>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "mandoline/tab/web_view_impl.h"

#include "components/view_manager/public/cpp/view.h"
#include "components/view_manager/public/cpp/view_manager.h"
#include "mandoline/tab/frame.h"
#include "mandoline/tab/frame_connection.h"
#include "mandoline/tab/frame_tree.h"
#include "mojo/application/public/cpp/application_impl.h"
#include "mojo/converters/geometry/geometry_type_converters.h"

// TODO(beng): remove once these classes are in the web_view namespace.
using mandoline::FrameTreeClient;
using mandoline::FrameConnection;

namespace web_view {

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, public:

WebViewImpl::WebViewImpl(mojo::ApplicationImpl* app,
                         mojom::WebViewClientPtr client,
                         mojo::InterfaceRequest<mojom::WebView> request)
    : app_(app),
      client_(client.Pass()),
      binding_(this, request.Pass()),
      content_(nullptr),
      view_manager_client_factory_(app->shell(), this) {
}

WebViewImpl::~WebViewImpl() {}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, WebView implementation:

void WebViewImpl::LoadRequest(mojo::URLRequestPtr request) {
  if (!content_) {
    // We haven't been embedded yet, store the request for when we are.
    pending_request_ = request.Pass();
    return;
  }
  scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
  mojo::ViewManagerClientPtr view_manager_client;
  frame_connection->Init(app_, request.Pass(), &view_manager_client);
  FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
  frame_tree_.reset(new FrameTree(content_, this, frame_tree_client,
                                  frame_connection.Pass()));
  content_->Embed(view_manager_client.Pass());
}

void WebViewImpl::GetViewManagerClient(
    mojo::InterfaceRequest<mojo::ViewManagerClient> view_manager_client) {
  view_manager_client_factory_.Create(nullptr, view_manager_client.Pass());
}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, mojo::ViewManagerDelegate implementation:

void WebViewImpl::OnEmbed(mojo::View* root) {
  root->view_manager()->SetEmbedRoot();
  root->AddObserver(this);
  content_ = root->view_manager()->CreateView();
  root->AddChild(content_);
  content_->SetVisible(true);
  content_->AddObserver(this);

  if (!pending_request_.is_null())
    LoadRequest(pending_request_.Pass());
}

void WebViewImpl::OnEmbedForDescendant(mojo::View* view,
                                       mojo::URLRequestPtr request,
                                       mojo::ViewManagerClientPtr* client) {
  // TODO(sky): move this to Frame/FrameTree.
  Frame* frame = Frame::FindFirstFrameAncestor(view);
  if (!frame || !frame->HasAncestor(frame_tree_->root())) {
    // TODO(sky): add requestor url so that we can return false if it's not
    // an app we expect.
    scoped_ptr<mojo::ApplicationConnection> connection =
        app_->ConnectToApplication(request.Pass());
    connection->ConnectToService(client);
    return;
  }

  scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
  frame_connection->Init(app_, request.Pass(), client);
  FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
  frame_tree_->CreateOrReplaceFrame(frame, view, frame_tree_client,
                                    frame_connection.Pass());
}

void WebViewImpl::OnViewManagerDestroyed(mojo::ViewManager* view_manager) {
}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, mojo::ViewObserver implementation:

void WebViewImpl::OnViewBoundsChanged(mojo::View* view,
                                      const mojo::Rect& old_bounds,
                                      const mojo::Rect& new_bounds) {
  if (view != content_) {
    mojo::Rect rect;
    rect.width = new_bounds.width;
    rect.height = new_bounds.height;
    content_->SetBounds(rect);
  }
}

void WebViewImpl::OnViewDestroyed(mojo::View* view) {
  // |FrameTree| cannot outlive the content view.
  if (view == content_)
    frame_tree_.reset();
}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, mandoline::FrameTreeDelegate implementation:

bool WebViewImpl::CanPostMessageEventToFrame(const Frame* source,
                                             const Frame* target,
                                             HTMLMessageEvent* event) {
  return true;
}

void WebViewImpl::LoadingStateChanged(bool loading) {
  client_->LoadingStateChanged(loading);
}

void WebViewImpl::ProgressChanged(double progress) {
  client_->ProgressChanged(progress);
}

void WebViewImpl::RequestNavigate(Frame* source,
                                  mandoline::NavigationTargetType target_type,
                                  Frame* target_frame,
                                  mojo::URLRequestPtr request) {
  // TODO: this needs security checks.
  if (target_type == mandoline::NAVIGATION_TARGET_TYPE_EXISTING_FRAME) {
    if (target_frame && target_frame != frame_tree_->root() &&
        target_frame->view()) {
      NavigateExistingFrame(target_frame, request.Pass());
      return;
    }
    DVLOG(1) << "RequestNavigate() targeted existing frame that doesn't exist.";
    return;
  }
  client_->TopLevelNavigate(request.Pass());
}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, private:

void WebViewImpl::NavigateExistingFrame(Frame* frame,
                                        mojo::URLRequestPtr request) {
  scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
  mojo::ViewManagerClientPtr view_manager_client;
  frame_connection->Init(app_, request.Pass(), &view_manager_client);
  frame->view()->Embed(view_manager_client.Pass());
  FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
  frame_tree_->CreateOrReplaceFrame(frame, frame->view(), frame_tree_client,
                                    frame_connection.Pass());
}

}  // namespace web_view
<commit_msg>Honors requests to navigate in existing frame for the root<commit_after>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "mandoline/tab/web_view_impl.h"

#include "components/view_manager/public/cpp/view.h"
#include "components/view_manager/public/cpp/view_manager.h"
#include "mandoline/tab/frame.h"
#include "mandoline/tab/frame_connection.h"
#include "mandoline/tab/frame_tree.h"
#include "mojo/application/public/cpp/application_impl.h"
#include "mojo/converters/geometry/geometry_type_converters.h"

// TODO(beng): remove once these classes are in the web_view namespace.
using mandoline::FrameTreeClient;
using mandoline::FrameConnection;

namespace web_view {

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, public:

WebViewImpl::WebViewImpl(mojo::ApplicationImpl* app,
                         mojom::WebViewClientPtr client,
                         mojo::InterfaceRequest<mojom::WebView> request)
    : app_(app),
      client_(client.Pass()),
      binding_(this, request.Pass()),
      content_(nullptr),
      view_manager_client_factory_(app->shell(), this) {
}

WebViewImpl::~WebViewImpl() {}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, WebView implementation:

void WebViewImpl::LoadRequest(mojo::URLRequestPtr request) {
  if (!content_) {
    // We haven't been embedded yet, store the request for when we are.
    pending_request_ = request.Pass();
    return;
  }
  scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
  mojo::ViewManagerClientPtr view_manager_client;
  frame_connection->Init(app_, request.Pass(), &view_manager_client);
  FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
  frame_tree_.reset(new FrameTree(content_, this, frame_tree_client,
                                  frame_connection.Pass()));
  content_->Embed(view_manager_client.Pass());
}

void WebViewImpl::GetViewManagerClient(
    mojo::InterfaceRequest<mojo::ViewManagerClient> view_manager_client) {
  view_manager_client_factory_.Create(nullptr, view_manager_client.Pass());
}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, mojo::ViewManagerDelegate implementation:

void WebViewImpl::OnEmbed(mojo::View* root) {
  root->view_manager()->SetEmbedRoot();
  root->AddObserver(this);
  content_ = root->view_manager()->CreateView();
  root->AddChild(content_);
  content_->SetVisible(true);
  content_->AddObserver(this);

  if (!pending_request_.is_null())
    LoadRequest(pending_request_.Pass());
}

void WebViewImpl::OnEmbedForDescendant(mojo::View* view,
                                       mojo::URLRequestPtr request,
                                       mojo::ViewManagerClientPtr* client) {
  // TODO(sky): move this to Frame/FrameTree.
  Frame* frame = Frame::FindFirstFrameAncestor(view);
  if (!frame || !frame->HasAncestor(frame_tree_->root())) {
    // TODO(sky): add requestor url so that we can return false if it's not
    // an app we expect.
    scoped_ptr<mojo::ApplicationConnection> connection =
        app_->ConnectToApplication(request.Pass());
    connection->ConnectToService(client);
    return;
  }

  scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
  frame_connection->Init(app_, request.Pass(), client);
  FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
  frame_tree_->CreateOrReplaceFrame(frame, view, frame_tree_client,
                                    frame_connection.Pass());
}

void WebViewImpl::OnViewManagerDestroyed(mojo::ViewManager* view_manager) {
}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, mojo::ViewObserver implementation:

void WebViewImpl::OnViewBoundsChanged(mojo::View* view,
                                      const mojo::Rect& old_bounds,
                                      const mojo::Rect& new_bounds) {
  if (view != content_) {
    mojo::Rect rect;
    rect.width = new_bounds.width;
    rect.height = new_bounds.height;
    content_->SetBounds(rect);
  }
}

void WebViewImpl::OnViewDestroyed(mojo::View* view) {
  // |FrameTree| cannot outlive the content view.
  if (view == content_)
    frame_tree_.reset();
}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, mandoline::FrameTreeDelegate implementation:

bool WebViewImpl::CanPostMessageEventToFrame(const Frame* source,
                                             const Frame* target,
                                             HTMLMessageEvent* event) {
  return true;
}

void WebViewImpl::LoadingStateChanged(bool loading) {
  client_->LoadingStateChanged(loading);
}

void WebViewImpl::ProgressChanged(double progress) {
  client_->ProgressChanged(progress);
}

void WebViewImpl::RequestNavigate(Frame* source,
                                  mandoline::NavigationTargetType target_type,
                                  Frame* target_frame,
                                  mojo::URLRequestPtr request) {
  // TODO: this needs security checks.
  if (target_type == mandoline::NAVIGATION_TARGET_TYPE_EXISTING_FRAME &&
      target_frame != frame_tree_->root()) {
    if (target_frame && target_frame->view()) {
      NavigateExistingFrame(target_frame, request.Pass());
      return;
    }
    DVLOG(1) << "RequestNavigate() targeted existing frame that doesn't exist.";
    return;
  }
  client_->TopLevelNavigate(request.Pass());
}

////////////////////////////////////////////////////////////////////////////////
// WebViewImpl, private:

void WebViewImpl::NavigateExistingFrame(Frame* frame,
                                        mojo::URLRequestPtr request) {
  scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
  mojo::ViewManagerClientPtr view_manager_client;
  frame_connection->Init(app_, request.Pass(), &view_manager_client);
  frame->view()->Embed(view_manager_client.Pass());
  FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
  frame_tree_->CreateOrReplaceFrame(frame, frame->view(), frame_tree_client,
                                    frame_connection.Pass());
}

}  // namespace web_view
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include "core/posix.hh"
#include "core/vla.hh"
#include "core/reactor.hh"
#include "core/future-util.hh"
#include "core/stream.hh"
#include "core/circular_buffer.hh"
#include "core/align.hh"
#include <atomic>
#include <list>
#include <queue>
#include <fcntl.h>
#include <linux/if_tun.h>
#include "ip.hh"

#include <xen/xen.h>

#include <xen/memory.h>
#include <xen/sys/gntalloc.h>

#include "core/xen/xenstore.hh"
#include "core/xen/evtchn.hh"

#include "xenfront.hh"
#include <unordered_set>

using namespace net;

using phys = uint64_t;

class xenfront_net_device : public net::device {
private:
    bool _userspace;
    stream<packet> _rx_stream;
    net::hw_features _hw_features;

    std::string _device_str;
    xenstore* _xenstore = xenstore::instance();
    unsigned _otherend;
    std::string _backend;
    gntalloc *_gntalloc;
    evtchn   *_evtchn;
    port *_tx_evtchn;
    port *_rx_evtchn;

    front_ring<tx> _tx_ring;
    front_ring<rx> _rx_ring;

    grant_head *_tx_refs;
    grant_head *_rx_refs;

    std::list<std::pair<std::string, std::string>> _features;
    static std::unordered_set<std::string> _supported_features;

    ethernet_address _hw_address;

    port *bind_tx_evtchn();
    port *bind_rx_evtchn();

    future<> alloc_rx_references();
    future<> handle_tx_completions();
    future<> queue_rx_packet();

    void alloc_one_rx_reference(unsigned id);
    std::string path(std::string s) { return _device_str + "/" + s; }

public:
    explicit xenfront_net_device(boost::program_options::variables_map opts, bool userspace);
    ~xenfront_net_device();
    virtual subscription<packet> receive(std::function<future<> (packet)> next) override;
    virtual future<> send(packet p) override;

    ethernet_address hw_address();
    net::hw_features hw_features();
};

std::unordered_set<std::string>
xenfront_net_device::_supported_features = {
    "feature-split-event-channels",
    "feature-rx-copy",
};

subscription<packet>
xenfront_net_device::receive(std::function<future<> (packet)> next) {
    auto sub = _rx_stream.listen(std::move(next));
    keep_doing([this] {
        return _rx_evtchn->pending().then([this] {
            return queue_rx_packet();
        });
    });

    return std::move(sub);
}

future<>
xenfront_net_device::send(packet _p) {

    uint32_t frag = 0;
    // There doesn't seem to be a way to tell xen, when using the userspace
    // drivers, to map a particular page. Therefore, the only alternative
    // here is to copy. All pages shared must come from the gntalloc mmap.
    //
    // A better solution could be to change the packet allocation path to
    // use a pre-determined page for data.
    //
    // In-kernel should be fine

    // FIXME: negotiate and use scatter/gather
    _p.linearize();

    return _tx_ring.entries.get_index().then([this, p = std::move(_p), frag] (unsigned idx) mutable {

        auto req_prod = _tx_ring._sring->req_prod;

        auto f = p.frag(frag);

        auto ref = _tx_refs->new_ref(f.base, f.size);

        assert(!_tx_ring.entries[idx]);

        _tx_ring.entries[idx] = ref;

        auto req = &_tx_ring._sring->_ring[idx].req;
        req->gref = ref.xen_id;
        req->offset = 0;
        req->flags = {};
        if (p.offload_info().protocol != ip_protocol_num::unused) {
            req->flags.csum_blank = true;
            req->flags.data_validated = true;
        } else {
            req->flags.data_validated = true;
        }
        req->id = idx;
        req->size = f.size;

        _tx_ring.req_prod_pvt = idx;
        _tx_ring._sring->req_prod = req_prod + 1;

        _tx_ring._sring->req_event++;
        if ((frag + 1) == p.nr_frags()) {
            _tx_evtchn->notify();
            return make_ready_future<>();
        } else {
            return make_ready_future<>();
        }
    });

    // FIXME: Don't forget to clear all grant refs when frontend closes. Or is it automatic?
}

#define rmb() asm volatile("lfence":::"memory");
#define wmb() asm volatile("":::"memory");

template <typename T>
future<unsigned> front_ring<T>::entries::get_index() {
    return _available.wait().then([this] {
        auto ret = _ids.front();
        _ids.pop();
        return make_ready_future<unsigned>(ret);
    });
}

template <typename T>
void front_ring<T>::entries::free_index(unsigned id) {
    _ids.push(id);
    _available.signal();
}

future<> xenfront_net_device::queue_rx_packet() {

    auto rsp_cons = _rx_ring.rsp_cons;
    rmb();
    auto rsp_prod = _rx_ring._sring->rsp_prod;

    while (rsp_cons < rsp_prod) {
        auto rsp = _rx_ring[rsp_cons].rsp;
        auto& entry = _rx_ring.entries[rsp.id];

        rsp_cons++;
        _rx_ring.rsp_cons = rsp_cons;

        if (rsp.status < 0) {
            printf("Packet error: Handle it\n");
            continue;
        }
        auto rsp_size = rsp.status;

        packet p(static_cast<char *>(entry.page) + rsp.offset, rsp_size);
        _rx_stream.produce(std::move(p));

        _rx_ring._sring->rsp_event = rsp_cons + 1;

        rsp_prod = _rx_ring._sring->rsp_prod;

        _rx_refs->free_ref(entry);
        _rx_ring.entries.free_index(rsp.id);
    }

    // FIXME: Queue_rx maybe should not be a future then
    return make_ready_future<>();
}

void xenfront_net_device::alloc_one_rx_reference(unsigned index) {

    _rx_ring.entries[index] = _rx_refs->new_ref();

    // This is how the backend knows where to put data.
    auto req =  &_rx_ring._sring->_ring[index].req;
    req->id = index;
    req->gref = _rx_ring.entries[index].xen_id;
}

future<> xenfront_net_device::alloc_rx_references() {
    return _rx_ring.entries.get_index().then([this] (unsigned i) {
        auto req_prod = _rx_ring.req_prod_pvt;
        alloc_one_rx_reference(i);
        ++req_prod;
        _rx_ring.req_prod_pvt = req_prod;
        wmb();
        _rx_ring._sring->req_prod = req_prod;
        /* ready */
        _rx_evtchn->notify();
    });
}

future<> xenfront_net_device::handle_tx_completions() {
    auto prod = _tx_ring._sring->rsp_prod;
    rmb();

    for (unsigned i = _tx_ring.rsp_cons; i != prod; i++) {
        auto rsp = _tx_ring[i].rsp;

        if (rsp.status == 1) {
            continue;
        }

        if (rsp.status != 0) {
            printf("Packet error: Handle it\n");
            continue;
        }

        auto& entry = _tx_ring.entries[rsp.id];
        _tx_refs->free_ref(entry);
        _tx_ring.entries.free_index(rsp.id);
    }
    _tx_ring.rsp_cons = prod;
    _tx_ring._sring->rsp_event = prod + 1;
    return make_ready_future<>();
}

ethernet_address xenfront_net_device::hw_address() {
    return _hw_address;
}

net::hw_features xenfront_net_device::hw_features() {
    return _hw_features;
}

port *xenfront_net_device::bind_tx_evtchn() {
    return _evtchn->bind();
}

port *xenfront_net_device::bind_rx_evtchn() {

    auto split = _xenstore->read(_backend + "/feature-split-event-channels");
    if (split != "") {
        return _evtchn->bind();
    }
    return _evtchn->bind(*_tx_evtchn);
}

xenfront_net_device::xenfront_net_device(boost::program_options::variables_map opts, bool userspace)
    : _userspace(userspace)
    , _rx_stream()
    , _device_str("device/vif/" + std::to_string(opts["vif"].as<unsigned>()))
    , _otherend(_xenstore->read<int>(path("backend-id")))
    , _backend(_xenstore->read(path("backend")))
    , _gntalloc(gntalloc::instance(_userspace, _otherend))
    , _evtchn(evtchn::instance(_userspace, _otherend))
    , _tx_evtchn(bind_tx_evtchn())
    , _rx_evtchn(bind_rx_evtchn())
    , _tx_ring(_gntalloc->alloc_ref())
    , _rx_ring(_gntalloc->alloc_ref())
    , _tx_refs(_gntalloc->alloc_ref(front_ring<tx>::nr_ents))
    , _rx_refs(_gntalloc->alloc_ref(front_ring<rx>::nr_ents))
    , _hw_address(net::parse_ethernet_address(_xenstore->read(path("mac")))) {

    _rx_stream.started();

    auto all_features = _xenstore->ls(_backend);
    std::unordered_map<std::string, int> features_nack;

    for (auto&& feat : all_features) {
        if (feat.compare(0, 8, "feature-") == 0 && !_supported_features.count(feat)) {
            features_nack[feat] = 0;
        }
    }

    _hw_features.rx_csum_offload = true;
    _hw_features.tx_csum_offload = true;

    for (auto&s : all_features) {
        auto value = _xenstore->read(_backend + "/" + s);
        _features.push_back(std::make_pair(s, value));
    }

    {
        auto t = xenstore::xenstore_transaction();

        for (auto&& f: features_nack) {
            _xenstore->write(path(f.first), f.second, t);
        }

        _xenstore->write<int>(path("event-channel-tx"), *_tx_evtchn, t);
        _xenstore->write<int>(path("event-channel-rx"), *_rx_evtchn, t);
        _xenstore->write<int>(path("tx-ring-ref"), _tx_ring.ref, t);
        _xenstore->write<int>(path("rx-ring-ref"), _rx_ring.ref, t);
        _xenstore->write<int>(path("state"), 4, t);
    }

    keep_doing([this] {
        return alloc_rx_references();
    });
    keep_doing([this] () {
        return _tx_evtchn->pending().then([this] {
            handle_tx_completions();
        });
    });
}

xenfront_net_device::~xenfront_net_device() {

    {
        auto t = xenstore::xenstore_transaction();

        for (auto& f: _features) {
            _xenstore->remove(path(f.first), t);
        }
        _xenstore->remove(path("event-channel-tx"), t);
        _xenstore->remove(path("event-channel-rx"), t);
        _xenstore->remove(path("tx-ring-ref"), t);
        _xenstore->remove(path("rx-ring-ref"), t);
        _xenstore->write<int>(path("state"), 6, t);
    }

    _xenstore->write<int>(path("state"), 1);
}

boost::program_options::options_description
get_xenfront_net_options_description() {

    boost::program_options::options_description opts(
            "xenfront net options");
    opts.add_options()
        ("vif",
                boost::program_options::value<unsigned>()->default_value(0),
                "vif number to hijack")
        ;
    return opts;
}

std::unique_ptr<net::device> create_xenfront_net_device(boost::program_options::variables_map opts, bool userspace) {
    auto ptr = std::make_unique<xenfront_net_device>(opts, userspace);
    // This assumes only one device per cpu. Will need to be fixed when
    // this assumption will no longer hold.
    dev = ptr.get();
    return std::move(ptr);
}
<commit_msg>xen: fix explicitly-disabled split event channel feature<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include "core/posix.hh"
#include "core/vla.hh"
#include "core/reactor.hh"
#include "core/future-util.hh"
#include "core/stream.hh"
#include "core/circular_buffer.hh"
#include "core/align.hh"
#include <atomic>
#include <list>
#include <queue>
#include <fcntl.h>
#include <linux/if_tun.h>
#include "ip.hh"

#include <xen/xen.h>

#include <xen/memory.h>
#include <xen/sys/gntalloc.h>

#include "core/xen/xenstore.hh"
#include "core/xen/evtchn.hh"

#include "xenfront.hh"
#include <unordered_set>

using namespace net;

using phys = uint64_t;

class xenfront_net_device : public net::device {
private:
    bool _userspace;
    stream<packet> _rx_stream;
    net::hw_features _hw_features;

    std::string _device_str;
    xenstore* _xenstore = xenstore::instance();
    unsigned _otherend;
    std::string _backend;
    gntalloc *_gntalloc;
    evtchn   *_evtchn;
    port *_tx_evtchn;
    port *_rx_evtchn;

    front_ring<tx> _tx_ring;
    front_ring<rx> _rx_ring;

    grant_head *_tx_refs;
    grant_head *_rx_refs;

    std::list<std::pair<std::string, std::string>> _features;
    static std::unordered_set<std::string> _supported_features;

    ethernet_address _hw_address;

    port *bind_tx_evtchn();
    port *bind_rx_evtchn();

    future<> alloc_rx_references();
    future<> handle_tx_completions();
    future<> queue_rx_packet();

    void alloc_one_rx_reference(unsigned id);
    std::string path(std::string s) { return _device_str + "/" + s; }

public:
    explicit xenfront_net_device(boost::program_options::variables_map opts, bool userspace);
    ~xenfront_net_device();
    virtual subscription<packet> receive(std::function<future<> (packet)> next) override;
    virtual future<> send(packet p) override;

    ethernet_address hw_address();
    net::hw_features hw_features();
};

std::unordered_set<std::string>
xenfront_net_device::_supported_features = {
    "feature-split-event-channels",
    "feature-rx-copy",
};

subscription<packet>
xenfront_net_device::receive(std::function<future<> (packet)> next) {
    auto sub = _rx_stream.listen(std::move(next));
    keep_doing([this] {
        return _rx_evtchn->pending().then([this] {
            return queue_rx_packet();
        });
    });

    return std::move(sub);
}

future<>
xenfront_net_device::send(packet _p) {

    uint32_t frag = 0;
    // There doesn't seem to be a way to tell xen, when using the userspace
    // drivers, to map a particular page. Therefore, the only alternative
    // here is to copy. All pages shared must come from the gntalloc mmap.
    //
    // A better solution could be to change the packet allocation path to
    // use a pre-determined page for data.
    //
    // In-kernel should be fine

    // FIXME: negotiate and use scatter/gather
    _p.linearize();

    return _tx_ring.entries.get_index().then([this, p = std::move(_p), frag] (unsigned idx) mutable {

        auto req_prod = _tx_ring._sring->req_prod;

        auto f = p.frag(frag);

        auto ref = _tx_refs->new_ref(f.base, f.size);

        assert(!_tx_ring.entries[idx]);

        _tx_ring.entries[idx] = ref;

        auto req = &_tx_ring._sring->_ring[idx].req;
        req->gref = ref.xen_id;
        req->offset = 0;
        req->flags = {};
        if (p.offload_info().protocol != ip_protocol_num::unused) {
            req->flags.csum_blank = true;
            req->flags.data_validated = true;
        } else {
            req->flags.data_validated = true;
        }
        req->id = idx;
        req->size = f.size;

        _tx_ring.req_prod_pvt = idx;
        _tx_ring._sring->req_prod = req_prod + 1;

        _tx_ring._sring->req_event++;
        if ((frag + 1) == p.nr_frags()) {
            _tx_evtchn->notify();
            return make_ready_future<>();
        } else {
            return make_ready_future<>();
        }
    });

    // FIXME: Don't forget to clear all grant refs when frontend closes. Or is it automatic?
}

#define rmb() asm volatile("lfence":::"memory");
#define wmb() asm volatile("":::"memory");

template <typename T>
future<unsigned> front_ring<T>::entries::get_index() {
    return _available.wait().then([this] {
        auto ret = _ids.front();
        _ids.pop();
        return make_ready_future<unsigned>(ret);
    });
}

template <typename T>
void front_ring<T>::entries::free_index(unsigned id) {
    _ids.push(id);
    _available.signal();
}

future<> xenfront_net_device::queue_rx_packet() {

    auto rsp_cons = _rx_ring.rsp_cons;
    rmb();
    auto rsp_prod = _rx_ring._sring->rsp_prod;

    while (rsp_cons < rsp_prod) {
        auto rsp = _rx_ring[rsp_cons].rsp;
        auto& entry = _rx_ring.entries[rsp.id];

        rsp_cons++;
        _rx_ring.rsp_cons = rsp_cons;

        if (rsp.status < 0) {
            printf("Packet error: Handle it\n");
            continue;
        }
        auto rsp_size = rsp.status;

        packet p(static_cast<char *>(entry.page) + rsp.offset, rsp_size);
        _rx_stream.produce(std::move(p));

        _rx_ring._sring->rsp_event = rsp_cons + 1;

        rsp_prod = _rx_ring._sring->rsp_prod;

        _rx_refs->free_ref(entry);
        _rx_ring.entries.free_index(rsp.id);
    }

    // FIXME: Queue_rx maybe should not be a future then
    return make_ready_future<>();
}

void xenfront_net_device::alloc_one_rx_reference(unsigned index) {

    _rx_ring.entries[index] = _rx_refs->new_ref();

    // This is how the backend knows where to put data.
    auto req =  &_rx_ring._sring->_ring[index].req;
    req->id = index;
    req->gref = _rx_ring.entries[index].xen_id;
}

future<> xenfront_net_device::alloc_rx_references() {
    return _rx_ring.entries.get_index().then([this] (unsigned i) {
        auto req_prod = _rx_ring.req_prod_pvt;
        alloc_one_rx_reference(i);
        ++req_prod;
        _rx_ring.req_prod_pvt = req_prod;
        wmb();
        _rx_ring._sring->req_prod = req_prod;
        /* ready */
        _rx_evtchn->notify();
    });
}

future<> xenfront_net_device::handle_tx_completions() {
    auto prod = _tx_ring._sring->rsp_prod;
    rmb();

    for (unsigned i = _tx_ring.rsp_cons; i != prod; i++) {
        auto rsp = _tx_ring[i].rsp;

        if (rsp.status == 1) {
            continue;
        }

        if (rsp.status != 0) {
            printf("Packet error: Handle it\n");
            continue;
        }

        auto& entry = _tx_ring.entries[rsp.id];
        _tx_refs->free_ref(entry);
        _tx_ring.entries.free_index(rsp.id);
    }
    _tx_ring.rsp_cons = prod;
    _tx_ring._sring->rsp_event = prod + 1;
    return make_ready_future<>();
}

ethernet_address xenfront_net_device::hw_address() {
    return _hw_address;
}

net::hw_features xenfront_net_device::hw_features() {
    return _hw_features;
}

port *xenfront_net_device::bind_tx_evtchn() {
    return _evtchn->bind();
}

port *xenfront_net_device::bind_rx_evtchn() {

    auto split = _xenstore->read_or_default<int>(_backend + "/feature-split-event-channels");
    if (split) {
        return _evtchn->bind();
    }
    return _evtchn->bind(*_tx_evtchn);
}

xenfront_net_device::xenfront_net_device(boost::program_options::variables_map opts, bool userspace)
    : _userspace(userspace)
    , _rx_stream()
    , _device_str("device/vif/" + std::to_string(opts["vif"].as<unsigned>()))
    , _otherend(_xenstore->read<int>(path("backend-id")))
    , _backend(_xenstore->read(path("backend")))
    , _gntalloc(gntalloc::instance(_userspace, _otherend))
    , _evtchn(evtchn::instance(_userspace, _otherend))
    , _tx_evtchn(bind_tx_evtchn())
    , _rx_evtchn(bind_rx_evtchn())
    , _tx_ring(_gntalloc->alloc_ref())
    , _rx_ring(_gntalloc->alloc_ref())
    , _tx_refs(_gntalloc->alloc_ref(front_ring<tx>::nr_ents))
    , _rx_refs(_gntalloc->alloc_ref(front_ring<rx>::nr_ents))
    , _hw_address(net::parse_ethernet_address(_xenstore->read(path("mac")))) {

    _rx_stream.started();

    auto all_features = _xenstore->ls(_backend);
    std::unordered_map<std::string, int> features_nack;

    for (auto&& feat : all_features) {
        if (feat.compare(0, 8, "feature-") == 0 && !_supported_features.count(feat)) {
            features_nack[feat] = 0;
        }
    }

    _hw_features.rx_csum_offload = true;
    _hw_features.tx_csum_offload = true;

    for (auto&s : all_features) {
        auto value = _xenstore->read(_backend + "/" + s);
        _features.push_back(std::make_pair(s, value));
    }

    {
        auto t = xenstore::xenstore_transaction();

        for (auto&& f: features_nack) {
            _xenstore->write(path(f.first), f.second, t);
        }

        _xenstore->write<int>(path("event-channel-tx"), *_tx_evtchn, t);
        _xenstore->write<int>(path("event-channel-rx"), *_rx_evtchn, t);
        _xenstore->write<int>(path("tx-ring-ref"), _tx_ring.ref, t);
        _xenstore->write<int>(path("rx-ring-ref"), _rx_ring.ref, t);
        _xenstore->write<int>(path("state"), 4, t);
    }

    keep_doing([this] {
        return alloc_rx_references();
    });
    keep_doing([this] () {
        return _tx_evtchn->pending().then([this] {
            handle_tx_completions();
        });
    });
}

xenfront_net_device::~xenfront_net_device() {

    {
        auto t = xenstore::xenstore_transaction();

        for (auto& f: _features) {
            _xenstore->remove(path(f.first), t);
        }
        _xenstore->remove(path("event-channel-tx"), t);
        _xenstore->remove(path("event-channel-rx"), t);
        _xenstore->remove(path("tx-ring-ref"), t);
        _xenstore->remove(path("rx-ring-ref"), t);
        _xenstore->write<int>(path("state"), 6, t);
    }

    _xenstore->write<int>(path("state"), 1);
}

boost::program_options::options_description
get_xenfront_net_options_description() {

    boost::program_options::options_description opts(
            "xenfront net options");
    opts.add_options()
        ("vif",
                boost::program_options::value<unsigned>()->default_value(0),
                "vif number to hijack")
        ;
    return opts;
}

std::unique_ptr<net::device> create_xenfront_net_device(boost::program_options::variables_map opts, bool userspace) {
    auto ptr = std::make_unique<xenfront_net_device>(opts, userspace);
    // This assumes only one device per cpu. Will need to be fixed when
    // this assumption will no longer hold.
    dev = ptr.get();
    return std::move(ptr);
}
<|endoftext|>


<commit_before>/*-------------netlist_gen.cpp------------------------------------------------//
*
*              netlist generator
*
* Purpose: The BIAS project intends to re-implement the TrueNorth architechture
*          in analog electronics. For this purpose, we will need to create a
*          simple script that will create a netlist to be read into a SPICE
*          simulator (or similar software that is compatable with the netlist
*          format.
*
*   Notes: This could be written a little cleaner in another language, but...
*          We need to determine the appropriate analog inputs for this file
*
*          To compile, use the following command:
*              g++ netlist_gen.cpp -std=c++11 -o genet
*
*  PEMDAS: We will place everything on a grid. The components we need are:
*              1. inverting amp
*              2. summing amp
*              3. differential amp
*              4. sample and hold
*
*          The grid will then be enumerated appropriately by filling the grid
*              points with integers and counting.
*
*          Finally, this will be written out to a file.
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

using namespace std;

/*----------------------------------------------------------------------------//
* STRUCTURES AND FUNCTIONS
*-----------------------------------------------------------------------------*/

struct resistor{

    double value;
    int forw, back;
};

struct capacitor{

    double value;
    int forw, back;

};

// opamps are weird in spice. They have 4 extremities:
// out, ground, in+, in-
struct opamp{
    int inp, inn, out;
};

// struct to pass output and index between functions
struct netlist{
    string str;
    int index;
};

// These functions will all take the current netlist and count and append the
// appropriate variables to it. These will be used in the larger f(x)'s below
netlist inv_amp(netlist net);
netlist sum_amp(netlist net, vector<resistor> connections);
netlist diff_amp(netlist net, int inp, int inn);
netlist samhold(netlist net);

// These functions will take care of connections and such within the core
netlist neuron(netlist net);
netlist junction(netlist net);
netlist connectome(netlist net);

// Quick function to write the netlist to a file
void write_netlist(netlist net, ofstream &output);

/*----------------------------------------------------------------------------//
* MAIN
*-----------------------------------------------------------------------------*/

int main(void){

    return 0;
}

/*----------------------------------------------------------------------------//
* SUBROUTINES
*-----------------------------------------------------------------------------*/

// These functions will all take the current netlist and count and append the
// appropriate variables to it. These will be used in the larger f(x)'s below

netlist inv_amp(netlist net){
    resistor res, res_2;
    opamp oa;

    // Setting initial values
    res.value = res_2.value = 1000;

    // Setting resistors in place
    res.back = net.index;
    res.forw = net.index + 1;
    res_2.back = net.index + 1;
    res_2.forw = net.index + 2;

    // Setting opamp up
    oa.inp = 0;
    oa.inn = net.index + 1;
    oa.out = net.index + 2;

    // appending to netlist

    // opamp
    net.str.append(" e" + to_string(net.index) + " " + to_string(oa.out) + " 0 "
                   + to_string(oa.inp) + " " + to_string(oa.inn) + " 999k");

    // R1
    net.str.append(" r" + to_string(res.back) + " " + to_string(res.forw) + " "
                   + to_string(res.value) + "k");

    // R2
    net.str.append(" r" + to_string(res_2.back) + " " + to_string(res_2.forw) +
                   " " + to_string(res.value) + "k");

    return net;
}

// Write out summing amp, including preceding resistors here.
// This function is simple because we are assuming we are reading in the R vals
netlist sum_amp(netlist net, vector<resistor> connections){

    opamp oa;
    resistor res;

    // For this function, it is assumed that all the incoming resistors are
    // of the same value

    for (auto &r : connections){
        r.forw = net.index;
        net.str.append(" r" + to_string(r.back) + " " + to_string(r.forw) +
                       " " + to_string(res.value) + "k");
    }

    //Setting up op amp
    oa.inp = 0;
    oa.inn = net.index;
    oa.out = net.index + 1;

    // setting up resistor
    res.back = net.index;
    res.forw = net.index + 1;
    res.value = connections[0].value;

    // appending to netlist

    // opamp
    net.str.append(" e" + to_string(net.index) + " " + to_string(oa.out) + " 0 "
                   + to_string(oa.inp) + " " + to_string(oa.inn) + " 999k");

    // Resistor
    net.str.append(" r" + to_string(res.back) + " " + to_string(res.forw) + " "
                   + to_string(res.value) + "k");

    return net;
}

netlist diff_amp(netlist net, int inp, int inn){
    return net;
}

netlist samhold(netlist net){
    return net;
}

// These functions will take care of connections and such within the core
netlist neuron(netlist net){
    return net;
}

netlist junction(netlist net){
    return net;
}

netlist connectome(netlist net){
    return net;
}

// Quick function to write the netlist to a file
void write_netlist(netlist net, ofstream &output){
}

<commit_msg>added the sample and hold and differential amplifier<commit_after>/*-------------netlist_gen.cpp------------------------------------------------//
*
*              netlist generator
*
* Purpose: The BIAS project intends to re-implement the TrueNorth architechture
*          in analog electronics. For this purpose, we will need to create a
*          simple script that will create a netlist to be read into a SPICE
*          simulator (or similar software that is compatable with the netlist
*          format.
*
*   Notes: This could be written a little cleaner in another language, but...
*          We need to determine the appropriate analog inputs for this file
*
*          To compile, use the following command:
*              g++ netlist_gen.cpp -std=c++11 -o genet
*
*  PEMDAS: We will place everything on a grid. The components we need are:
*              1. inverting amp
*              2. summing amp
*              3. differential amp
*              4. sample and hold
*
*          The grid will then be enumerated appropriately by filling the grid
*              points with integers and counting.
*
*          Finally, this will be written out to a file.
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

using namespace std;

/*----------------------------------------------------------------------------//
* STRUCTURES AND FUNCTIONS
*-----------------------------------------------------------------------------*/

struct resistor{

    double value;
    int forw, back;
};

struct capacitor{

    double value;
    int forw, back;

};

// opamps are weird in spice. They have 4 extremities:
// out, ground, in+, in-
struct opamp{
    int inp, inn, out;
};

// struct to pass output and index between functions
struct netlist{
    string str;
    int index;
};

// These functions will all take the current netlist and count and append the
// appropriate variables to it. These will be used in the larger f(x)'s below
netlist inv_amp(netlist net);
netlist sum_amp(netlist net, vector<resistor> connections);
netlist diff_amp(netlist net, resistor inrp, resistor inrn);
netlist samhold(netlist net);

// These functions will take care of connections and such within the core
netlist neuron(netlist net);
netlist junction(netlist net);
netlist connectome(netlist net);

// Quick function to write the netlist to a file
void write_netlist(netlist net, ofstream &output);

/*----------------------------------------------------------------------------//
* MAIN
*-----------------------------------------------------------------------------*/

int main(void){

    return 0;
}

/*----------------------------------------------------------------------------//
* SUBROUTINES
*-----------------------------------------------------------------------------*/

// These functions will all take the current netlist and count and append the
// appropriate variables to it. These will be used in the larger f(x)'s below

netlist inv_amp(netlist net){
    resistor res, res_2;
    opamp oa;

    // Setting initial values
    res.value = res_2.value = 1000;

    // Setting resistors in place
    res.back = net.index;
    res.forw = net.index + 1;
    res_2.back = net.index + 1;
    res_2.forw = net.index + 2;

    // Setting opamp up
    oa.inp = 0;
    oa.inn = net.index + 1;
    oa.out = net.index + 2;

    // appending to netlist

    // opamp
    net.str.append(" e" + to_string(net.index) + " " + to_string(oa.out) + " 0 "
                   + to_string(oa.inp) + " " + to_string(oa.inn) + " 999k");

    // R1
    net.str.append(" r" + to_string(res.back) + " " + to_string(res.forw) + " "
                   + to_string(res.value) + "k");

    // R2
    net.str.append(" r" + to_string(res_2.back) + " " + to_string(res_2.forw) +
                   " " + to_string(res.value) + "k");

    net.index++;

    return net;
}

// Write out summing amp, including preceding resistors here.
// This function is simple because we are assuming we are reading in the R vals
netlist sum_amp(netlist net, vector<resistor> connections){

    opamp oa;
    resistor res;

    // For this function, it is assumed that all the incoming resistors are
    // of the same value

    for (auto &r : connections){
        r.forw = net.index;
        net.str.append(" r" + to_string(r.back) + " " + to_string(r.forw) +
                       " " + to_string(res.value) + "k");
    }

    //Setting up op amp
    oa.inp = 0;
    oa.inn = net.index;
    oa.out = net.index + 1;

    // setting up resistor
    res.back = net.index;
    res.forw = net.index + 1;
    res.value = connections[0].value;

    // appending to netlist

    // opamp
    net.str.append(" e" + to_string(net.index) + " " + to_string(oa.out) + " 0 "
                   + to_string(oa.inp) + " " + to_string(oa.inn) + " 999k");

    // Resistor
    net.str.append(" r" + to_string(res.back) + " " + to_string(res.forw) + " "
                   + to_string(res.value) + "k");

    net.index++;

    return net;
}

// Because we only want the differences between the voltages, we do not need
// to worry about different resistor values.
// Like the summing amplifier, its easier to read in resistors than ints and
// write them here.
netlist diff_amp(netlist net, resistor inrp, resistor inrn){

    opamp oa;
    // Note: No resistor def necessary since all resistor values are the same

    // First, let's write out the resistors we have coming in
    inrp.forw = net.index + 1;
    inrn.forw = net.index;
    net.str.append(" r" + to_string(inrp.back) + " " + to_string(inrp.forw) +" "
                   + to_string(inrp.value) + "k");
    net.str.append(" r" + to_string(inrn.back) + " " + to_string(inrn.forw) +" "
                   + to_string(inrn.value) + "k");

    // Now we need to create the rest of the differential amplifier circuit

    // r2 clone to ground
    net.str.append(" r" + to_string(inrp.forw) + " " + to_string(0) +" "
                   + to_string(inrp.value) + "k");

    // r1 clone to out
    net.str.append(" r" + to_string(inrn.forw) + " " + to_string(net.index + 2)
                   + " " + to_string(inrn.value) + "k");

    // opamp definitions and writing

    oa.inp = inrp.forw;
    oa.inn = inrn.forw;
    // Note +2 instead of +1 due to two inputs
    oa.out = net.index + 2;

    net.str.append(" e" + to_string(net.index) + " " + to_string(oa.out) + " 0 "
                   + to_string(oa.inp) + " " + to_string(oa.inn) + " 999k");

    net.index += 2;

    return net;
}

// This iteration of a sample and hold circuit will not have FET switches.
// To implement FET switches, just put on the output of oa1 for charging, and
// another parallel to the capacitor for discarging
netlist samhold(netlist net){

    opamp oa1, oa2;
    capacitor cap;

    // opamp1
    oa1.inp = 0;
    oa1.inn = net.index;
    oa1.out = net.index + 1;

    // opamp2
    oa2.inp = 0;
    oa2.inn = net.index + 1;
    oa2.out = net.index + 2;

    // capacitor
    cap.back = net.index + 1;
    cap.forw = 0;

    //appending to netlist
    // opamp
    net.str.append(" e"+to_string(net.index)+" "+to_string(oa1.out)+" 0 "
                   + to_string(oa1.inp) + " " + to_string(oa1.inn) + " 999k");

    net.str.append(" e"+to_string(net.index+1)+" "+to_string(oa2.out)+" 0 "
                   + to_string(oa2.inp) + " " + to_string(oa2.inn) + " 999k");

    // Resistor
    net.str.append(" c" + to_string(cap.back) + " " + to_string(cap.forw) + " "
                   + to_string(cap.value) + "k");

    net.index += 2;

    return net;
}

// These functions will take care of connections and such within the core
netlist neuron(netlist net){
    return net;
}

netlist junction(netlist net){
    return net;
}

netlist connectome(netlist net){
    return net;
}

// Quick function to write the netlist to a file
void write_netlist(netlist net, ofstream &output){
}

<|endoftext|>


<commit_before>/**************************************************************************************/
/*                                                                                */
/*  Visualization Library                                                             */
/*  http://www.visualizationlibrary.org                                               */
/*                                                                                */
/*  Copyright (c) 2005-2010, Michele Bosi                                             */
/*  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.                                   */
/*                                                                                */
/*  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 <vlGraphics/SceneManagerPortals.hpp>
#include <vlGraphics/Geometry.hpp>
#include <vlCore/Say.hpp>
#include <vlGraphics/Camera.hpp>

using namespace vl;

//-----------------------------------------------------------------------------
// Portal
//-----------------------------------------------------------------------------
bool Portal::computeNormal()
{
  mNormal = 0;
  if (geometry().size() < 3)
  {
    vl::Log::error("Portal::computeNormal() error, no portal geometry defined.\n");
    return false;
  }
  if (!mTargetSector)
  {
    vl::Log::error("Portal::computeNormal() error, no sector bound to this portal.\n");
    return false;
  }

  fvec3 v0 = geometry()[0];
  fvec3 v1 = geometry()[1] - v0;
  fvec3 v2 = geometry()[2] - v0;
  mNormal = cross(v1,v2);

  return true;
}
//-----------------------------------------------------------------------------
// Sector
//-----------------------------------------------------------------------------
AABB Sector::computeBoundingBox()
{
  AABB aabb;
  for(int i=0; i<actors()->size(); ++i)
  {
    actors()->at(i)->computeBounds();
    aabb += actors()->at(i)->boundingBox();
  }
  return aabb;
}
//-----------------------------------------------------------------------------
void Sector::executeCallbacks(const Camera*cam,SceneManagerPortals* psm, Portal*p)
{
  for(unsigned i=0; i<callbacks().size(); ++i)
    callbacks()[i]->operator()(cam,psm,this,p);
}
//-----------------------------------------------------------------------------
// SceneManagerPortals
//-----------------------------------------------------------------------------
void SceneManagerPortals::initialize()
{
  computePortalNormals();
  for(unsigned i=0; i<mSectors.size(); ++i)
  {
    if (mSectors[i]->volumes().empty())
      vl::Log::error( vl::Say("Sector #%n does not have any volume!\n") << i );
    for(unsigned j=0; j<mSectors[i]->portals().size(); ++j)
      if (!mSectors[i]->portals()[j]->targetSector())
        vl::Log::error( vl::Say("In Sector #%n Portal #%n does not have any target sector!\n") << i << j);
  }
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::renderPortal(Portal* portal)
{
  if (mPortalActorMap.find(portal) == mPortalActorMap.end())
  {
    const fvec4 portal_color = fvec4(1,0,0,0.25f);
    vl::ref<vl::Effect> portal_fx = new vl::Effect;
    /*portal_fx->shader()->enable(vl::EN_DEPTH_TEST);
    portal_fx->shader()->gocDepthFunc()->set(vl::FU_LEQUAL);*/
    portal_fx->shader()->enable(vl::EN_BLEND);
    portal_fx->shader()->gocLineWidth()->set(2.0f);
    portal_fx->shader()->gocColor()->setValue(portal_color);

    vl::ref<vl::Geometry> portal_geom = new vl::Geometry;
    vl::ref<vl::ArrayFloat3> vert_array = new vl::ArrayFloat3;
    portal_geom->setVertexArray(vert_array.get());
    vert_array->resize(portal->geometry().size());
    for(unsigned int i=0; i<portal->geometry().size(); ++i)
      vert_array->at(i) = portal->geometry()[i];
    portal_geom->drawCalls()->push_back( new vl::DrawArrays(vl::PT_LINE_LOOP, 0, (int)vert_array->size()) );
#if defined(VL_OPENGL)
    portal_geom->drawCalls()->push_back( new vl::DrawArrays(vl::PT_POLYGON,   0, (int)vert_array->size()) );
#endif
    mPortalActorMap[portal] = new vl::Actor(portal_geom.get(), portal_fx.get(), NULL);
  }
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::extractActors(ActorCollection& list)
{
  for(unsigned i=0; i<mSectors.size(); ++i)
    for(int j=0; j<mSectors[i]->actors()->size(); ++j)
      list.push_back( mSectors[i]->actors()->at(j) );
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::extractVisibleActors(ActorCollection& list, const Camera* camera)
{
  if (cullingEnabled())
  {
    Sector* start = computeStartingSector(camera);
    if (!start)
      extractActors(list);
    else
    {
      ++mVisitTick;
      mTempActors.clear();
      mFrustumStack.clear();

      mFrustumStack.push_back(camera->frustum());
      start->executeCallbacks(camera,this,NULL);
      visitSector(NULL, start, camera->modelingMatrix().getT(), camera);

      // insert portal actors
      if (showPortals())
      {
        for(std::map<Portal*, ref<Actor> >::const_iterator it = mPortalActorMap.begin(); it != mPortalActorMap.end(); ++it)
          mTempActors.push_back(it->second);
      }

      // mic fixme: isn't quicker to use sets instead of sort()+unique()?
      // avoid reporting duplicates
      std::sort(mTempActors.begin(), mTempActors.end());
      std::vector< ref<Actor> >::iterator new_end = std::unique(mTempActors.begin(), mTempActors.end());
      for(std::vector< ref<Actor> >::iterator it = mTempActors.begin(); it != new_end; ++it)
        list.push_back(it->get());
    }
  }
  else
    extractActors(list);
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::visitSector(Sector* prev, Sector* sector, const vec3& eye, const Camera* camera)
{
  // this sector is visible so we add the visible objects
  for(int j=0; j<sector->actors()->size(); ++j)
  {
    if (isEnabled(sector->actors()->at(j)))
    {
      sector->actors()->at(j)->computeBounds();
      bool visible = true;
      for(unsigned i=0; visible && i<mFrustumStack.size(); ++i)
        visible = visible & !mFrustumStack[i].cull( sector->actors()->at(j)->boundingBox() );
      if( visible )
        mTempActors.push_back( sector->actors()->at(j) );
    }
  }
  // check the visible portals
  for(unsigned j=0; j<sector->portals().size(); ++j)
  {
    if(showPortals())
      renderPortal(sector->portals()[j].get());

    // open/closed portals.
    if(!sector->portals()[j]->isOpen())
      continue;

    if (sector->portals()[j]->mVisitTick == mVisitTick)
      continue;
    else
      sector->portals()[j]->mVisitTick = mVisitTick;

    Sector* target_sec = sector->portals()[j]->targetSector();
    VL_CHECK(target_sec != sector)
    if ( target_sec != prev )
    {
      bool visible = true;
      for(unsigned i=0; visible && i<mFrustumStack.size(); ++i)
        visible = visible & !mFrustumStack[i].cull( sector->portals()[j]->geometry() );

      if (visible)
      {
        // make visiting_portal_frustum
        Frustum portal_frustum;
        portal_frustum.planes().resize(sector->portals()[j]->geometry().size());
        bool flip = dot((fvec3)eye - sector->portals()[j]->geometry()[0], sector->portals()[j]->normal()) < 0;
        for(unsigned i=0; i<sector->portals()[j]->geometry().size(); ++i)
        {
          int i2 = (i+1) % sector->portals()[j]->geometry().size();
          vec3 v1 = (vec3)sector->portals()[j]->geometry()[i]  - eye;
          vec3 v2 = (vec3)sector->portals()[j]->geometry()[i2] - eye;
          vec3 n = cross(v1,v2);
          n.normalize();
          if (flip)
            n = -n;
          portal_frustum.setPlane(i, Plane(dot(n,eye),n));
        }

        mFrustumStack.push_back(portal_frustum);
        sector->executeCallbacks(camera,this,sector->portals()[j].get());
        visitSector(sector, sector->portals()[j]->targetSector(), eye, camera);
        mFrustumStack.pop_back();
      }
    }
  }
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::computePortalNormals()
{
  for(unsigned i=0; i<mSectors.size(); ++i)
    for(unsigned j=0; j<mSectors[i]->portals().size(); ++j)
      mSectors[i]->portals()[j]->computeNormal();
}
//-----------------------------------------------------------------------------
Sector* SceneManagerPortals::computeStartingSector(const Camera* camera)
{
  vec3 eye = camera->modelingMatrix().getT();
  for(unsigned i=0; i<mSectors.size(); ++i)
  {
    for(unsigned j=0; j<mSectors[i]->volumes().size(); ++j)
    {
      if (sectors()[i]->volumes()[j].isInside(eye))
        return sectors()[i].get();
    }
  }
  return externalSector();
}
//-----------------------------------------------------------------------------
<commit_msg>SceneManagerPortals.cpp fixed rendering of portals.<commit_after>/**************************************************************************************/
/*                                                                                */
/*  Visualization Library                                                             */
/*  http://www.visualizationlibrary.org                                               */
/*                                                                                */
/*  Copyright (c) 2005-2010, Michele Bosi                                             */
/*  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.                                   */
/*                                                                                */
/*  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 <vlGraphics/SceneManagerPortals.hpp>
#include <vlGraphics/Geometry.hpp>
#include <vlCore/Say.hpp>
#include <vlGraphics/Camera.hpp>

using namespace vl;

//-----------------------------------------------------------------------------
// Portal
//-----------------------------------------------------------------------------
bool Portal::computeNormal()
{
  mNormal = 0;
  if (geometry().size() < 3)
  {
    vl::Log::error("Portal::computeNormal() error, no portal geometry defined.\n");
    return false;
  }
  if (!mTargetSector)
  {
    vl::Log::error("Portal::computeNormal() error, no sector bound to this portal.\n");
    return false;
  }

  fvec3 v0 = geometry()[0];
  fvec3 v1 = geometry()[1] - v0;
  fvec3 v2 = geometry()[2] - v0;
  mNormal = cross(v1,v2);

  return true;
}
//-----------------------------------------------------------------------------
// Sector
//-----------------------------------------------------------------------------
AABB Sector::computeBoundingBox()
{
  AABB aabb;
  for(int i=0; i<actors()->size(); ++i)
  {
    actors()->at(i)->computeBounds();
    aabb += actors()->at(i)->boundingBox();
  }
  return aabb;
}
//-----------------------------------------------------------------------------
void Sector::executeCallbacks(const Camera*cam,SceneManagerPortals* psm, Portal*p)
{
  for(unsigned i=0; i<callbacks().size(); ++i)
    callbacks()[i]->operator()(cam,psm,this,p);
}
//-----------------------------------------------------------------------------
// SceneManagerPortals
//-----------------------------------------------------------------------------
void SceneManagerPortals::initialize()
{
  computePortalNormals();
  for(unsigned i=0; i<mSectors.size(); ++i)
  {
    if (mSectors[i]->volumes().empty())
      vl::Log::error( vl::Say("Sector #%n does not have any volume!\n") << i );
    for(unsigned j=0; j<mSectors[i]->portals().size(); ++j)
      if (!mSectors[i]->portals()[j]->targetSector())
        vl::Log::error( vl::Say("In Sector #%n Portal #%n does not have any target sector!\n") << i << j);
  }
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::renderPortal(Portal* portal)
{
  std::map<Portal*, ref<Actor> >::iterator it = mPortalActorMap.find(portal);
  if (it == mPortalActorMap.end())
  {
    const fvec4 portal_color = fvec4(1,0,0,0.25f);
    vl::ref<vl::Effect> portal_fx = new vl::Effect;
    /*portal_fx->shader()->enable(vl::EN_DEPTH_TEST);
    portal_fx->shader()->gocDepthFunc()->set(vl::FU_LEQUAL);*/
    portal_fx->shader()->enable(vl::EN_BLEND);
    portal_fx->shader()->gocLineWidth()->set(2.0f);
    portal_fx->shader()->gocColor()->setValue(portal_color);

    vl::ref<vl::Geometry> portal_geom = new vl::Geometry;
    vl::ref<vl::ArrayFloat3> vert_array = new vl::ArrayFloat3;
    portal_geom->setVertexArray(vert_array.get());
    vert_array->resize(portal->geometry().size());
    for(unsigned int i=0; i<portal->geometry().size(); ++i)
      vert_array->at(i) = portal->geometry()[i];
    portal_geom->drawCalls()->push_back( new vl::DrawArrays(vl::PT_LINE_LOOP, 0, (int)vert_array->size()) );
#if defined(VL_OPENGL)
    portal_geom->drawCalls()->push_back( new vl::DrawArrays(vl::PT_POLYGON,   0, (int)vert_array->size()) );
#endif
    ref<Actor> actor = new vl::Actor(portal_geom.get(), portal_fx.get(), NULL);
    mPortalActorMap[portal] = actor;
    mTempActors.push_back(actor);
  }
  else
    mTempActors.push_back(it->second);
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::extractActors(ActorCollection& list)
{
  for(unsigned i=0; i<mSectors.size(); ++i)
    for(int j=0; j<mSectors[i]->actors()->size(); ++j)
      list.push_back( mSectors[i]->actors()->at(j) );
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::extractVisibleActors(ActorCollection& list, const Camera* camera)
{
  if (cullingEnabled())
  {
    Sector* start = computeStartingSector(camera);
    if (!start)
      extractActors(list);
    else
    {
      ++mVisitTick;
      mTempActors.clear();
      mFrustumStack.clear();

      mFrustumStack.push_back(camera->frustum());
      start->executeCallbacks(camera,this,NULL);
      visitSector(NULL, start, camera->modelingMatrix().getT(), camera);

      // remove duplicates
      std::sort(mTempActors.begin(), mTempActors.end());
      std::vector< ref<Actor> >::iterator new_end = std::unique(mTempActors.begin(), mTempActors.end());
      for(std::vector< ref<Actor> >::iterator it = mTempActors.begin(); it != new_end; ++it)
        list.push_back(it->get());
    }
  }
  else
    extractActors(list);
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::visitSector(Sector* prev, Sector* sector, const vec3& eye, const Camera* camera)
{
  // this sector is visible so we add the visible objects
  for(int j=0; j<sector->actors()->size(); ++j)
  {
    if (isEnabled(sector->actors()->at(j)))
    {
      sector->actors()->at(j)->computeBounds();
      bool visible = true;
      for(unsigned i=0; visible && i<mFrustumStack.size(); ++i)
        visible = visible & !mFrustumStack[i].cull( sector->actors()->at(j)->boundingBox() );
      if( visible )
        mTempActors.push_back( sector->actors()->at(j) );
    }
  }
  // check the visible portals
  for(unsigned j=0; j<sector->portals().size(); ++j)
  {
    if(showPortals())
      renderPortal(sector->portals()[j].get());

    // open/closed portals.
    if(!sector->portals()[j]->isOpen())
      continue;

    if (sector->portals()[j]->mVisitTick == mVisitTick)
      continue;
    else
      sector->portals()[j]->mVisitTick = mVisitTick;

    Sector* target_sec = sector->portals()[j]->targetSector();
    VL_CHECK(target_sec != sector)
    if ( target_sec != prev )
    {
      bool visible = true;
      for(unsigned i=0; visible && i<mFrustumStack.size(); ++i)
        visible = visible & !mFrustumStack[i].cull( sector->portals()[j]->geometry() );

      if (visible)
      {
        // make visiting_portal_frustum
        Frustum portal_frustum;
        portal_frustum.planes().resize(sector->portals()[j]->geometry().size());
        bool flip = dot((fvec3)eye - sector->portals()[j]->geometry()[0], sector->portals()[j]->normal()) < 0;
        for(unsigned i=0; i<sector->portals()[j]->geometry().size(); ++i)
        {
          int i2 = (i+1) % sector->portals()[j]->geometry().size();
          vec3 v1 = (vec3)sector->portals()[j]->geometry()[i]  - eye;
          vec3 v2 = (vec3)sector->portals()[j]->geometry()[i2] - eye;
          vec3 n = cross(v1,v2);
          n.normalize();
          if (flip)
            n = -n;
          portal_frustum.setPlane(i, Plane(dot(n,eye),n));
        }

        mFrustumStack.push_back(portal_frustum);
        sector->executeCallbacks(camera,this,sector->portals()[j].get());
        visitSector(sector, sector->portals()[j]->targetSector(), eye, camera);
        mFrustumStack.pop_back();
      }
    }
  }
}
//-----------------------------------------------------------------------------
void SceneManagerPortals::computePortalNormals()
{
  for(unsigned i=0; i<mSectors.size(); ++i)
    for(unsigned j=0; j<mSectors[i]->portals().size(); ++j)
      mSectors[i]->portals()[j]->computeNormal();
}
//-----------------------------------------------------------------------------
Sector* SceneManagerPortals::computeStartingSector(const Camera* camera)
{
  vec3 eye = camera->modelingMatrix().getT();
  for(unsigned i=0; i<mSectors.size(); ++i)
  {
    for(unsigned j=0; j<mSectors[i]->volumes().size(); ++j)
    {
      if (sectors()[i]->volumes()[j].isInside(eye))
        return sectors()[i].get();
    }
  }
  return externalSector();
}
//-----------------------------------------------------------------------------
<|endoftext|>


<commit_before><commit_msg>fix: GAMxVEN register class<commit_after><|endoftext|>


<commit_before>#ifndef MIMOSA_FORMAT_FORMAT_STREAM_HH
# define MIMOSA_FORMAT_FORMAT_STREAM_HH

# include "format.hh"
# include "../stream/stream.hh"

namespace mimosa
{
  namespace format
  {
    template <typename ... Args>
    inline
    bool format(stream::Stream::Ptr stream,
                runtime::Time       timeout,
                const char *        fmt,
                Args ...            args)
    {
      std::string str(format::str(fmt, args...));
      int64_t bytes = stream->loopWrite(str.data(), str.size(), timeout);
      return static_cast<std::string::size_type> (bytes) == str.size();
    }

    template <typename ... Args>
    inline
    bool format(stream::Stream::Ptr stream,
                const char *        fmt,
                Args ...            args)
    {
      return format(stream, static_cast<runtime::Time>(0), fmt, args...);
    }
  }
}

#endif /* !MIMOSA_FORMAT_FORMAT_STREAM_HH */
<commit_msg>Fixed a case where the formated string is empty<commit_after>#ifndef MIMOSA_FORMAT_FORMAT_STREAM_HH
# define MIMOSA_FORMAT_FORMAT_STREAM_HH

# include "format.hh"
# include "../stream/stream.hh"

namespace mimosa
{
  namespace format
  {
    template <typename ... Args>
    inline
    bool format(stream::Stream::Ptr stream,
                runtime::Time       timeout,
                const char *        fmt,
                Args ...            args)
    {
      std::string str(format::str(fmt, args...));
      if (str.empty())
        return true;
      int64_t bytes = stream->loopWrite(str.data(), str.size(), timeout);
      return static_cast<std::string::size_type> (bytes) == str.size();
    }

    template <typename ... Args>
    inline
    bool format(stream::Stream::Ptr stream,
                const char *        fmt,
                Args ...            args)
    {
      return format(stream, static_cast<runtime::Time>(0), fmt, args...);
    }
  }
}

#endif /* !MIMOSA_FORMAT_FORMAT_STREAM_HH */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: svarray.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 15:23:09 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"

#define _SVARRAY_CXX

#define _SVSTDARR_BOOLS
#define _SVSTDARR_BYTES
#define _SVSTDARR_ULONGS
#define _SVSTDARR_ULONGSSORT
#define _SVSTDARR_USHORTS
#define _SVSTDARR_LONGS
#define _SVSTDARR_LONGSSORT
#define _SVSTDARR_SHORTS
#define _SVSTDARR_STRINGS
#define _SVSTDARR_STRINGSDTOR
#define _SVSTDARR_STRINGSSORT
#define _SVSTDARR_STRINGSSORTDTOR
#define _SVSTDARR_STRINGSISORT
#define _SVSTDARR_STRINGSISORTDTOR
#define _SVSTDARR_USHORTSSORT

#define _SVSTDARR_BYTESTRINGS
#define _SVSTDARR_BYTESTRINGSDTOR
#define _SVSTDARR_BYTESTRINGSSORT
#define _SVSTDARR_BYTESTRINGSSORTDTOR
#define _SVSTDARR_BYTESTRINGSISORT
#define _SVSTDARR_BYTESTRINGSISORTDTOR

#define _SVSTDARR_XUB_STRLEN
#define _SVSTDARR_XUB_STRLENSORT

#include <svstdarr.hxx>

#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX //autogen
#include <tools/debug.hxx>
#endif

#ifdef MAC
#pragma segment NEVER_PURGE
#endif

SV_IMPL_VARARR(SvPtrarr,VoidPtr)
SV_IMPL_VARARR_PLAIN(SvPtrarrPlain,VoidPtr)

USHORT SvPtrarr::GetPos( const VoidPtr& aElement ) const
{   USHORT n;
    for( n=0; n < nA && *(GetData()+n) != aElement; ) n++;
    return ( n >= nA ? USHRT_MAX : n );
}

USHORT SvPtrarrPlain::GetPos( const VoidPtr aElement ) const
{   USHORT n;
    for( n=0; n < nA && *(GetData()+n) != aElement; ) n++;
    return ( n >= nA ? USHRT_MAX : n );
}

SV_IMPL_VARARR( SvBools, BOOL )
SV_IMPL_VARARR( SvBytes, BYTE )
SV_IMPL_VARARR( SvULongs, ULONG )
SV_IMPL_VARARR( SvUShorts, USHORT )
SV_IMPL_VARARR( SvLongs, long)
SV_IMPL_VARARR( SvShorts, short )

SV_IMPL_VARARR_SORT( SvULongsSort, ULONG )
SV_IMPL_VARARR_SORT( SvLongsSort, long )
SV_IMPL_VARARR_SORT( SvXub_StrLensSort, xub_StrLen )

SV_IMPL_VARARR( SvXub_StrLens, xub_StrLen )

SV_IMPL_PTRARR( SvStrings, StringPtr )
SV_IMPL_PTRARR( SvStringsDtor, StringPtr )
SV_IMPL_OP_PTRARR_SORT( SvStringsSort, StringPtr )
SV_IMPL_OP_PTRARR_SORT( SvStringsSortDtor, StringPtr )

SV_IMPL_PTRARR( SvByteStrings, ByteStringPtr )
SV_IMPL_PTRARR( SvByteStringsDtor, ByteStringPtr )
SV_IMPL_OP_PTRARR_SORT( SvByteStringsSort, ByteStringPtr )
SV_IMPL_OP_PTRARR_SORT( SvByteStringsSortDtor, ByteStringPtr )

// ---------------- strings -------------------------------------

// Array mit anderer Seek-Methode!
_SV_IMPL_SORTAR_ALG( SvStringsISort, StringPtr )
void SvStringsISort::DeleteAndDestroy( USHORT nP, USHORT nL )
{
    if( nL )
    {
        DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
        for( USHORT n=nP; n < nP + nL; n++ )
            delete *((StringPtr*)pData+n);
        SvPtrarr::Remove( nP, nL );
    }
}
BOOL SvStringsISort::Seek_Entry( const StringPtr aE, USHORT* pP ) const
{
    register USHORT nO  = SvStringsISort_SAR::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            StringCompare eCmp = (*((StringPtr*)pData + nM))->
                                        CompareIgnoreCaseToAscii( *(aE) );
            if( COMPARE_EQUAL == eCmp )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( COMPARE_LESS == eCmp )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

// ---------------- strings -------------------------------------

// Array mit anderer Seek-Methode!
_SV_IMPL_SORTAR_ALG( SvStringsISortDtor, StringPtr )
void SvStringsISortDtor::DeleteAndDestroy( USHORT nP, USHORT nL )
{
    if( nL )
    {
        DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
        for( USHORT n=nP; n < nP + nL; n++ )
            delete *((StringPtr*)pData+n);
        SvPtrarr::Remove( nP, nL );
    }
}
BOOL SvStringsISortDtor::Seek_Entry( const StringPtr aE, USHORT* pP ) const
{
    register USHORT nO  = SvStringsISortDtor_SAR::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            StringCompare eCmp = (*((StringPtr*)pData + nM))->
                                    CompareIgnoreCaseToAscii( *(aE) );
            if( COMPARE_EQUAL == eCmp )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( COMPARE_LESS == eCmp )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

// ---------------- Ushorts -------------------------------------

/* SortArray fuer UShorts */
BOOL SvUShortsSort::Seek_Entry( const USHORT aE, USHORT* pP ) const
{
    register USHORT nO  = SvUShorts::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            if( *(pData + nM) == aE )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( *(pData + nM) < aE )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

void SvUShortsSort::Insert( const SvUShortsSort * pI, USHORT nS, USHORT nE )
{
    if( USHRT_MAX == nE )
        nE = pI->Count();
    USHORT nP;
    const USHORT * pIArr = pI->GetData();
    for( ; nS < nE; ++nS )
    {
        if( ! Seek_Entry( *(pIArr+nS), &nP) )
                SvUShorts::Insert( *(pIArr+nS), nP );
        if( ++nP >= Count() )
        {
            SvUShorts::Insert( pI, nP, nS+1, nE );
            nS = nE;
        }
    }
}

BOOL SvUShortsSort::Insert( const USHORT aE )
{
    USHORT nP;
    BOOL bExist = Seek_Entry( aE, &nP );
    if( !bExist )
        SvUShorts::Insert( aE, nP );
    return !bExist;
}

BOOL SvUShortsSort::Insert( const USHORT aE, USHORT& rP )
{
    BOOL bExist = Seek_Entry( aE, &rP );
    if( !bExist )
        SvUShorts::Insert( aE, rP );
    return !bExist;
}

void SvUShortsSort::Insert( const USHORT* pE, USHORT nL)
{
    USHORT nP;
    for( USHORT n = 0; n < nL; ++n )
        if( ! Seek_Entry( *(pE+n), &nP ))
            SvUShorts::Insert( *(pE+n), nP );
}

// remove ab Pos
void SvUShortsSort::RemoveAt( const USHORT nP, USHORT nL )
{
    if( nL )
        SvUShorts::Remove( nP, nL);
}

// remove ab dem Eintrag
void SvUShortsSort::Remove( const USHORT aE, USHORT nL )
{
    USHORT nP;
    if( nL && Seek_Entry( aE, &nP ) )
        SvUShorts::Remove( nP, nL);
}

// ---------------- bytestrings -------------------------------------

// Array mit anderer Seek-Methode!
_SV_IMPL_SORTAR_ALG( SvByteStringsISort, ByteStringPtr )
void SvByteStringsISort::DeleteAndDestroy( USHORT nP, USHORT nL )
{
    if( nL )
    {
        DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
        for( USHORT n=nP; n < nP + nL; n++ )
            delete *((ByteStringPtr*)pData+n);
        SvPtrarr::Remove( nP, nL );
    }
}
BOOL SvByteStringsISort::Seek_Entry( const ByteStringPtr aE, USHORT* pP ) const
{
    register USHORT nO  = SvByteStringsISort_SAR::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            StringCompare eCmp = (*((ByteStringPtr*)pData + nM))->
                        CompareIgnoreCaseToAscii( *(aE) );
            if( COMPARE_EQUAL == eCmp )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( COMPARE_LESS == eCmp )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

// Array mit anderer Seek-Methode!
_SV_IMPL_SORTAR_ALG( SvByteStringsISortDtor, ByteStringPtr )
void SvByteStringsISortDtor::DeleteAndDestroy( USHORT nP, USHORT nL )
{
    if( nL )
    {
        DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
        for( USHORT n=nP; n < nP + nL; n++ )
            delete *((ByteStringPtr*)pData+n);
        SvPtrarr::Remove( nP, nL );
    }
}
BOOL SvByteStringsISortDtor::Seek_Entry( const ByteStringPtr aE, USHORT* pP ) const
{
    register USHORT nO  = SvByteStringsISortDtor_SAR::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            StringCompare eCmp = (*((ByteStringPtr*)pData + nM))->
                                    CompareIgnoreCaseToAscii( *(aE) );
            if( COMPARE_EQUAL == eCmp )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( COMPARE_LESS == eCmp )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

<commit_msg>INTEGRATION: CWS vgbugs07 (1.5.182); FILE MERGED 2007/06/04 13:31:42 vg 1.5.182.1: #i76605# Remove -I .../inc/module hack introduced by hedaburemove01<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: svarray.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 21:48:00 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"

#define _SVARRAY_CXX

#define _SVSTDARR_BOOLS
#define _SVSTDARR_BYTES
#define _SVSTDARR_ULONGS
#define _SVSTDARR_ULONGSSORT
#define _SVSTDARR_USHORTS
#define _SVSTDARR_LONGS
#define _SVSTDARR_LONGSSORT
#define _SVSTDARR_SHORTS
#define _SVSTDARR_STRINGS
#define _SVSTDARR_STRINGSDTOR
#define _SVSTDARR_STRINGSSORT
#define _SVSTDARR_STRINGSSORTDTOR
#define _SVSTDARR_STRINGSISORT
#define _SVSTDARR_STRINGSISORTDTOR
#define _SVSTDARR_USHORTSSORT

#define _SVSTDARR_BYTESTRINGS
#define _SVSTDARR_BYTESTRINGSDTOR
#define _SVSTDARR_BYTESTRINGSSORT
#define _SVSTDARR_BYTESTRINGSSORTDTOR
#define _SVSTDARR_BYTESTRINGSISORT
#define _SVSTDARR_BYTESTRINGSISORTDTOR

#define _SVSTDARR_XUB_STRLEN
#define _SVSTDARR_XUB_STRLENSORT

#include <svtools/svstdarr.hxx>

#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX //autogen
#include <tools/debug.hxx>
#endif

#ifdef MAC
#pragma segment NEVER_PURGE
#endif

SV_IMPL_VARARR(SvPtrarr,VoidPtr)
SV_IMPL_VARARR_PLAIN(SvPtrarrPlain,VoidPtr)

USHORT SvPtrarr::GetPos( const VoidPtr& aElement ) const
{   USHORT n;
    for( n=0; n < nA && *(GetData()+n) != aElement; ) n++;
    return ( n >= nA ? USHRT_MAX : n );
}

USHORT SvPtrarrPlain::GetPos( const VoidPtr aElement ) const
{   USHORT n;
    for( n=0; n < nA && *(GetData()+n) != aElement; ) n++;
    return ( n >= nA ? USHRT_MAX : n );
}

SV_IMPL_VARARR( SvBools, BOOL )
SV_IMPL_VARARR( SvBytes, BYTE )
SV_IMPL_VARARR( SvULongs, ULONG )
SV_IMPL_VARARR( SvUShorts, USHORT )
SV_IMPL_VARARR( SvLongs, long)
SV_IMPL_VARARR( SvShorts, short )

SV_IMPL_VARARR_SORT( SvULongsSort, ULONG )
SV_IMPL_VARARR_SORT( SvLongsSort, long )
SV_IMPL_VARARR_SORT( SvXub_StrLensSort, xub_StrLen )

SV_IMPL_VARARR( SvXub_StrLens, xub_StrLen )

SV_IMPL_PTRARR( SvStrings, StringPtr )
SV_IMPL_PTRARR( SvStringsDtor, StringPtr )
SV_IMPL_OP_PTRARR_SORT( SvStringsSort, StringPtr )
SV_IMPL_OP_PTRARR_SORT( SvStringsSortDtor, StringPtr )

SV_IMPL_PTRARR( SvByteStrings, ByteStringPtr )
SV_IMPL_PTRARR( SvByteStringsDtor, ByteStringPtr )
SV_IMPL_OP_PTRARR_SORT( SvByteStringsSort, ByteStringPtr )
SV_IMPL_OP_PTRARR_SORT( SvByteStringsSortDtor, ByteStringPtr )

// ---------------- strings -------------------------------------

// Array mit anderer Seek-Methode!
_SV_IMPL_SORTAR_ALG( SvStringsISort, StringPtr )
void SvStringsISort::DeleteAndDestroy( USHORT nP, USHORT nL )
{
    if( nL )
    {
        DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
        for( USHORT n=nP; n < nP + nL; n++ )
            delete *((StringPtr*)pData+n);
        SvPtrarr::Remove( nP, nL );
    }
}
BOOL SvStringsISort::Seek_Entry( const StringPtr aE, USHORT* pP ) const
{
    register USHORT nO  = SvStringsISort_SAR::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            StringCompare eCmp = (*((StringPtr*)pData + nM))->
                                        CompareIgnoreCaseToAscii( *(aE) );
            if( COMPARE_EQUAL == eCmp )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( COMPARE_LESS == eCmp )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

// ---------------- strings -------------------------------------

// Array mit anderer Seek-Methode!
_SV_IMPL_SORTAR_ALG( SvStringsISortDtor, StringPtr )
void SvStringsISortDtor::DeleteAndDestroy( USHORT nP, USHORT nL )
{
    if( nL )
    {
        DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
        for( USHORT n=nP; n < nP + nL; n++ )
            delete *((StringPtr*)pData+n);
        SvPtrarr::Remove( nP, nL );
    }
}
BOOL SvStringsISortDtor::Seek_Entry( const StringPtr aE, USHORT* pP ) const
{
    register USHORT nO  = SvStringsISortDtor_SAR::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            StringCompare eCmp = (*((StringPtr*)pData + nM))->
                                    CompareIgnoreCaseToAscii( *(aE) );
            if( COMPARE_EQUAL == eCmp )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( COMPARE_LESS == eCmp )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

// ---------------- Ushorts -------------------------------------

/* SortArray fuer UShorts */
BOOL SvUShortsSort::Seek_Entry( const USHORT aE, USHORT* pP ) const
{
    register USHORT nO  = SvUShorts::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            if( *(pData + nM) == aE )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( *(pData + nM) < aE )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

void SvUShortsSort::Insert( const SvUShortsSort * pI, USHORT nS, USHORT nE )
{
    if( USHRT_MAX == nE )
        nE = pI->Count();
    USHORT nP;
    const USHORT * pIArr = pI->GetData();
    for( ; nS < nE; ++nS )
    {
        if( ! Seek_Entry( *(pIArr+nS), &nP) )
                SvUShorts::Insert( *(pIArr+nS), nP );
        if( ++nP >= Count() )
        {
            SvUShorts::Insert( pI, nP, nS+1, nE );
            nS = nE;
        }
    }
}

BOOL SvUShortsSort::Insert( const USHORT aE )
{
    USHORT nP;
    BOOL bExist = Seek_Entry( aE, &nP );
    if( !bExist )
        SvUShorts::Insert( aE, nP );
    return !bExist;
}

BOOL SvUShortsSort::Insert( const USHORT aE, USHORT& rP )
{
    BOOL bExist = Seek_Entry( aE, &rP );
    if( !bExist )
        SvUShorts::Insert( aE, rP );
    return !bExist;
}

void SvUShortsSort::Insert( const USHORT* pE, USHORT nL)
{
    USHORT nP;
    for( USHORT n = 0; n < nL; ++n )
        if( ! Seek_Entry( *(pE+n), &nP ))
            SvUShorts::Insert( *(pE+n), nP );
}

// remove ab Pos
void SvUShortsSort::RemoveAt( const USHORT nP, USHORT nL )
{
    if( nL )
        SvUShorts::Remove( nP, nL);
}

// remove ab dem Eintrag
void SvUShortsSort::Remove( const USHORT aE, USHORT nL )
{
    USHORT nP;
    if( nL && Seek_Entry( aE, &nP ) )
        SvUShorts::Remove( nP, nL);
}

// ---------------- bytestrings -------------------------------------

// Array mit anderer Seek-Methode!
_SV_IMPL_SORTAR_ALG( SvByteStringsISort, ByteStringPtr )
void SvByteStringsISort::DeleteAndDestroy( USHORT nP, USHORT nL )
{
    if( nL )
    {
        DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
        for( USHORT n=nP; n < nP + nL; n++ )
            delete *((ByteStringPtr*)pData+n);
        SvPtrarr::Remove( nP, nL );
    }
}
BOOL SvByteStringsISort::Seek_Entry( const ByteStringPtr aE, USHORT* pP ) const
{
    register USHORT nO  = SvByteStringsISort_SAR::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            StringCompare eCmp = (*((ByteStringPtr*)pData + nM))->
                        CompareIgnoreCaseToAscii( *(aE) );
            if( COMPARE_EQUAL == eCmp )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( COMPARE_LESS == eCmp )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

// Array mit anderer Seek-Methode!
_SV_IMPL_SORTAR_ALG( SvByteStringsISortDtor, ByteStringPtr )
void SvByteStringsISortDtor::DeleteAndDestroy( USHORT nP, USHORT nL )
{
    if( nL )
    {
        DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
        for( USHORT n=nP; n < nP + nL; n++ )
            delete *((ByteStringPtr*)pData+n);
        SvPtrarr::Remove( nP, nL );
    }
}
BOOL SvByteStringsISortDtor::Seek_Entry( const ByteStringPtr aE, USHORT* pP ) const
{
    register USHORT nO  = SvByteStringsISortDtor_SAR::Count(),
            nM,
            nU = 0;
    if( nO > 0 )
    {
        nO--;
        while( nU <= nO )
        {
            nM = nU + ( nO - nU ) / 2;
            StringCompare eCmp = (*((ByteStringPtr*)pData + nM))->
                                    CompareIgnoreCaseToAscii( *(aE) );
            if( COMPARE_EQUAL == eCmp )
            {
                if( pP ) *pP = nM;
                return TRUE;
            }
            else if( COMPARE_LESS == eCmp )
                nU = nM + 1;
            else if( nM == 0 )
            {
                if( pP ) *pP = nU;
                return FALSE;
            }
            else
                nO = nM - 1;
        }
    }
    if( pP ) *pP = nU;
    return FALSE;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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 "PhotonWaveOut.h"

static WaveOut *current = NULL;

static void playback_handler(void) {
  int v = current->advance();
  // manual PWM, we map value to pulse-width
  if (v >= 0x80) {
    v = 0xFF-v;
    if (v > 0) {
      pinSetFast(current->pin_n);
      delayMicroseconds(v);
      pinResetFast(current->pin_n);
    }
  } else {
    if (v > 0) {
      pinSetFast(current->pin_p);
      delayMicroseconds(v);
      pinResetFast(current->pin_p);
    }
  }
}

bool WaveOut::play(char *wave, unsigned int wave_len, bool loop) {
  if (playing)
    stop();

  this->wave = wave;
  this->wave_len = wave_len;
  this->loop = loop;
  this->wave_ix = 0;
  current = this;
  // for 8000 Hz this should be 125, but we cheat a bit to be able to map the samples straight
  audio_clock->begin(playback_handler, 127, uSec);
  this->playing = true;
  return true;
}

void WaveOut::stop(void) {
  if (!playing)
    return;

  audio_clock->end();
  pinResetFast(pin_p);
  pinResetFast(pin_n);
  this->playing = false;
  current = NULL;
}

int WaveOut::advance(void) {
  int v = wave[wave_ix];
  wave_ix++;
  if (wave_ix >= wave_len) {
    wave_ix = 0;
    // TODO: do loop = false
  }
  return v;
}

<commit_msg>Add loop support.<commit_after>/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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 "PhotonWaveOut.h"

static WaveOut *current = NULL;

static void playback_handler(void) {
  int v = current->advance();
  // manual PWM, we map value to pulse-width
  if (v >= 0x80) {
    v = 0xFF-v;
    if (v > 0) {
      pinSetFast(current->pin_n);
      delayMicroseconds(v);
      pinResetFast(current->pin_n);
    }
  } else {
    if (v > 0) {
      pinSetFast(current->pin_p);
      delayMicroseconds(v);
      pinResetFast(current->pin_p);
    }
  }
}

bool WaveOut::play(char *wave, unsigned int wave_len, bool loop) {
  if (playing)
    stop();

  this->wave = wave;
  this->wave_len = wave_len;
  this->loop = loop;
  this->wave_ix = 0;
  current = this;
  // for 8000 Hz this should be 125, but we cheat a bit to be able to map the samples straight
  audio_clock->begin(playback_handler, 127, uSec);
  this->playing = true;
  return true;
}

void WaveOut::stop(void) {
  if (!playing)
    return;

  audio_clock->end();
  pinResetFast(pin_p);
  pinResetFast(pin_n);
  this->playing = false;
  current = NULL;
}

int WaveOut::advance(void) {
  int v = wave[wave_ix];
  wave_ix++;
  if (wave_ix >= wave_len) {
    if (loop) {
      wave_ix = 0;
    } else {
      stop();
    }
  }
  return v;
}

<|endoftext|>