<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2017 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include "PythonMacros.h"

#include "Binding_PythonScriptController.h"
#include "Binding_BaseObject.h"

using namespace sofa::component::controller;

#include <sofa/simulation/Node.h>
using namespace sofa::simulation;
using namespace sofa::core::objectmodel;

#include <sofa/helper/logging/Messaging.h>

// These functions are empty ones: they are meant to be overriden by real python
// controller scripts

// #define LOG_UNIMPLEMENTED_METHODS // prints a message each time a
// non-implemented (in the script) method is called

// TODO FIXME the above will not work (see FIXMEs below)

// also, can we PLEASE STOP COPYPASTING EVERYTHING KTHXBY

template<class T>
static inline T* get(PyObject* obj) {
    // functions plz
    return dynamic_cast<T*>(((PySPtr<Base>*)obj)->object.get());
}

static inline PythonScriptController* get_controller(PyObject* obj) {
    return get<PythonScriptController>(obj);
}

static PyObject * PythonScriptController_onIdle(PyObject * /*self*/, PyObject * args) {
    (void) args;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented out
    PythonScriptController* obj = get_controller(self);
     msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                         << ".onIdle not implemented in "
                                         << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onLoaded(PyObject * /*self*/, PyObject * args) {
    PyObject *pyNode;
    if (!PyArg_ParseTuple(args, "O", &pyNode)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    Node* node = get<Node>(pyNode);
    msg_error("PythonScriptController")<< obj->m_classname.getValueString()
                                       << ".onLoaded not implemented in "
                                       << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_createGraph(PyObject * /*self*/, PyObject * args) {
    PyObject *pyNode;
    if (!PyArg_ParseTuple(args, "O", &pyNode)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    Node* node = get<Node>(pyNode);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".createGraph not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_initGraph(PyObject * /*self*/, PyObject * args) {
    PyObject *pyNode;
    if (!PyArg_ParseTuple(args, "O", &pyNode)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    Node* node = get<Node>(pyNode);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".initGraph not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_bwdInitGraph(PyObject * /*self*/, PyObject * args) {
    PyObject *pyNode;
    if (!PyArg_ParseTuple(args, "O", &pyNode)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    Node* node = get<Node>(pyNode);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".bwdInitGraph not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onBeginAnimationStep(PyObject * /*self*/, PyObject * args) {
    double dt;
    if (!PyArg_ParseTuple(args, "d", &dt)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onBeginAnimationStep not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onEndAnimationStep(PyObject * /*self*/, PyObject * args) {
    double dt;
    if (!PyArg_ParseTuple(args, "d", &dt)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onEndAnimationStep not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_storeResetState(PyObject * /*self*/, PyObject * /*args*/) {

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".storeresetState not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_reset(PyObject * /*self*/, PyObject * /*args*/)  {

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".reset not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_cleanup(PyObject * /*self*/, PyObject * /*args*/) {

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".cleanup not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onGUIEvent(PyObject * /*self*/, PyObject * args) {
    char* controlID;
    char* valueName;
    char* value;
    if (!PyArg_ParseTuple(args, "sss", &controlID, &valueName,&value)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onGUIEvent not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onKeyPressed(PyObject * /*self*/, PyObject * args) {
    char k;
    if (!PyArg_ParseTuple(args, "c", &k)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onKeyPressed not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_FALSE;
}

static PyObject * PythonScriptController_onKeyReleased(PyObject * /*self*/, PyObject * args) {
    char k;
    if (!PyArg_ParseTuple(args, "c", &k)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onKeyReleased not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_FALSE;
}

static PyObject * PythonScriptController_onMouseButtonLeft(PyObject * /*self*/, PyObject * args) {
    int x, y;
    bool pressed;
    if (!PyArg_ParseTuple(args, "iib", &x, &y, &pressed)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onMouseButtonLeft not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onMouseButtonMiddle(PyObject * /*self*/, PyObject * args) {
    int x, y;
    bool pressed;
    if (!PyArg_ParseTuple(args, "iib", &x, &y, &pressed)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onMouseButtonMiddle not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onMouseButtonRight(PyObject * /*self*/, PyObject * args) {
    int x, y;
    bool pressed;
    if (!PyArg_ParseTuple(args, "iib", &x, &y, &pressed)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onMouseButtonRight not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onMouseWheel(PyObject * /*self*/, PyObject * args) {
    int x, y, delta;
    if (!PyArg_ParseTuple(args, "iii",&x, &y, &delta)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onMouseWheel not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

// TOOD here

static PyObject * PythonScriptController_onScriptEvent(PyObject * /*self*/, PyObject * args) {
    PyObject *pySenderNode;
    char* eventName;
    PyObject *pyData;
    if (!PyArg_ParseTuple(args, "OsO", &pySenderNode, &eventName, &pyData)) {
        return NULL;
    }

    BaseNode* senderBaseNode = ((PySPtr<Base>*)pySenderNode)->object->toBaseNode();
    if (!senderBaseNode) {
        // TODO this should not happen
        PyErr_SetString(PyExc_RuntimeError, "null node wtf");
        return NULL;
    }

    // TODO check pyData

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onScriptEvent not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_draw(PyObject * /*self*/, PyObject * /*args*/) {

#ifdef LOG_UNIMPLEMENTED_METHODS
    // TODO FIXME self is commented
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".draw not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onEvent(PyObject * /*self*/, PyObject * /*args*/) {
    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_instance(PyObject * self, PyObject * /*args*/) {
    PythonScriptController* obj = get_controller(self);
    return obj->scriptControllerInstance();
}

struct error { };

template<class T>
static inline T* operator || (T* obj, error e) {
    if(!obj) throw e;
    return obj;
}

static PyObject * PythonScriptController_new(PyTypeObject * cls, PyObject * args, PyObject* kwargs) {

    try {
        PyObject* py_node = PyTuple_GetItem(args, 0) || error();
        BaseContext* ctx = get<BaseContext>(py_node) || error();

        using controller_type = PythonScriptController;
        controller_type::SPtr controller = New<controller_type>();

        // note: original bindings **require** the controller to be wrapped as a
        // Base. virtual inheritance between Base and PythonScriptController
        // have been cleaned since then, so is should be safe to 1. wrap
        // directly as a PythonScriptController and 2. static_cast wrapped
        // pointers
        PyObject* instance = BuildPySPtr<Base>(controller.get(), cls);
        controller->setInstance(instance);

        ctx->addObject( controller );

        return instance;

    } catch (error e) {
        PyErr_SetString(PyExc_TypeError,
                        "PythonScriptController.__new__ needs a Sofa.BaseContext as first argument");
        return NULL;
    };
}

SP_CLASS_METHODS_BEGIN(PythonScriptController)
SP_CLASS_METHOD(PythonScriptController, onLoaded)
SP_CLASS_METHOD(PythonScriptController, createGraph)
SP_CLASS_METHOD(PythonScriptController, initGraph)
SP_CLASS_METHOD(PythonScriptController, bwdInitGraph)
SP_CLASS_METHOD(PythonScriptController, onKeyPressed)
SP_CLASS_METHOD(PythonScriptController, onKeyReleased)
SP_CLASS_METHOD(PythonScriptController, onMouseButtonLeft)
SP_CLASS_METHOD(PythonScriptController, onMouseButtonRight)
SP_CLASS_METHOD(PythonScriptController, onMouseButtonMiddle)
SP_CLASS_METHOD(PythonScriptController, onMouseWheel)
SP_CLASS_METHOD(PythonScriptController, onBeginAnimationStep)
SP_CLASS_METHOD(PythonScriptController, onEndAnimationStep)
SP_CLASS_METHOD(PythonScriptController, storeResetState)
SP_CLASS_METHOD(PythonScriptController, reset)
SP_CLASS_METHOD(PythonScriptController, cleanup)
SP_CLASS_METHOD(PythonScriptController, onGUIEvent)
SP_CLASS_METHOD(PythonScriptController, onScriptEvent)
SP_CLASS_METHOD(PythonScriptController, draw)
SP_CLASS_METHOD(PythonScriptController, onEvent)
SP_CLASS_METHOD(PythonScriptController, onIdle)
SP_CLASS_METHOD(PythonScriptController, instance)
SP_CLASS_METHODS_END;

static struct patch {

    patch() {
        // because i can
        SP_SOFAPYTYPEOBJECT(PythonScriptController).tp_new = PythonScriptController_new;
    }

} patcher;

SP_CLASS_TYPE_SPTR(PythonScriptController, PythonScriptController, BaseObject);
<commit_msg>[SofaPython] got rid of FIXMEs (thanks emacs macros)<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2017 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include "PythonMacros.h"

#include "Binding_PythonScriptController.h"
#include "Binding_BaseObject.h"

using namespace sofa::component::controller;

#include <sofa/simulation/Node.h>
using namespace sofa::simulation;
using namespace sofa::core::objectmodel;

#include <sofa/helper/logging/Messaging.h>

// These functions are empty ones: they are meant to be overriden by real python
// controller scripts

// #define LOG_UNIMPLEMENTED_METHODS // prints a message each time a
// non-implemented (in the script) method is called

// also, can we PLEASE STOP COPYPASTING EVERYTHING KTHXBY

template<class T>
static inline T* get(PyObject* obj) {
    // functions plz
    return dynamic_cast<T*>(((PySPtr<Base>*)obj)->object.get());
}

static inline PythonScriptController* get_controller(PyObject* obj) {
    return get<PythonScriptController>(obj);
}

static PyObject * PythonScriptController_onIdle(PyObject * self, PyObject * args) {
    (void) args; (void) self;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
     msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                         << ".onIdle not implemented in "
                                         << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onLoaded(PyObject * self, PyObject * args) {
    (void) self;

    PyObject *pyNode;
    if (!PyArg_ParseTuple(args, "O", &pyNode)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    Node* node = get<Node>(pyNode);
    msg_error("PythonScriptController")<< obj->m_classname.getValueString()
                                       << ".onLoaded not implemented in "
                                       << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_createGraph(PyObject * /*self*/, PyObject * args) {
    PyObject *pyNode;
    if (!PyArg_ParseTuple(args, "O", &pyNode)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    Node* node = get<Node>(pyNode);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".createGraph not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_initGraph(PyObject * self, PyObject * args) {
    (void) self;

    PyObject *pyNode;
    if (!PyArg_ParseTuple(args, "O", &pyNode)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    Node* node = get<Node>(pyNode);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".initGraph not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_bwdInitGraph(PyObject * self, PyObject * args) {
    (void) self;

    PyObject *pyNode;
    if (!PyArg_ParseTuple(args, "O", &pyNode)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    Node* node = get<Node>(pyNode);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".bwdInitGraph not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onBeginAnimationStep(PyObject * self, PyObject * args) {
    (void) self;

    double dt;
    if (!PyArg_ParseTuple(args, "d", &dt)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onBeginAnimationStep not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onEndAnimationStep(PyObject * self, PyObject * args) {
    (void) self;

    double dt;
    if (!PyArg_ParseTuple(args, "d", &dt)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onEndAnimationStep not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_storeResetState(PyObject * self, PyObject * /*args*/) {
    (void) self;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".storeresetState not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_reset(PyObject * self, PyObject * /*args*/)  {
    (void) self;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".reset not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_cleanup(PyObject * self, PyObject * /*args*/) {
    (void) self;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".cleanup not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onGUIEvent(PyObject * self, PyObject * args) {
    (void) self;

    char* controlID;
    char* valueName;
    char* value;
    if (!PyArg_ParseTuple(args, "sss", &controlID, &valueName,&value)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onGUIEvent not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onKeyPressed(PyObject * self, PyObject * args) {
    (void) self;

    char k;
    if (!PyArg_ParseTuple(args, "c", &k)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onKeyPressed not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_FALSE;
}

static PyObject * PythonScriptController_onKeyReleased(PyObject * self, PyObject * args) {
    (void) self;

    char k;
    if (!PyArg_ParseTuple(args, "c", &k)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onKeyReleased not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_FALSE;
}

static PyObject * PythonScriptController_onMouseButtonLeft(PyObject * self, PyObject * args) {
    (void) self;

    int x, y;
    bool pressed;
    if (!PyArg_ParseTuple(args, "iib", &x, &y, &pressed)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onMouseButtonLeft not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onMouseButtonMiddle(PyObject * self, PyObject * args) {
    (void) self;

    int x, y;
    bool pressed;
    if (!PyArg_ParseTuple(args, "iib", &x, &y, &pressed)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onMouseButtonMiddle not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onMouseButtonRight(PyObject * self, PyObject * args) {
    (void) self;

    int x, y;
    bool pressed;
    if (!PyArg_ParseTuple(args, "iib", &x, &y, &pressed)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onMouseButtonRight not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onMouseWheel(PyObject * self, PyObject * args) {
    (void) self;

    int x, y, delta;
    if (!PyArg_ParseTuple(args, "iii",&x, &y, &delta)) return NULL;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onMouseWheel not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onScriptEvent(PyObject * self, PyObject * args) {
    (void) self;

    PyObject *pySenderNode;
    char* eventName;
    PyObject *pyData;
    if (!PyArg_ParseTuple(args, "OsO", &pySenderNode, &eventName, &pyData)) {
        return NULL;
    }

    BaseNode* senderBaseNode = ((PySPtr<Base>*)pySenderNode)->object->toBaseNode();
    if (!senderBaseNode) {
        // TODO this should not happen
        PyErr_SetString(PyExc_RuntimeError, "null node wtf");
        return NULL;
    }

    // TODO check pyData

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".onScriptEvent not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_draw(PyObject * self, PyObject * /*args*/) {
    (void) self;

#ifdef LOG_UNIMPLEMENTED_METHODS
    PythonScriptController* obj = get_controller(self);
    msg_error("PythonScriptController") << obj->m_classname.getValueString()
                                        << ".draw not implemented in "
                                        << obj->name.getValueString() << std::endl;
#endif

    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_onEvent(PyObject * /*self*/, PyObject * /*args*/) {
    Py_RETURN_NONE;
}

static PyObject * PythonScriptController_instance(PyObject * self, PyObject * /*args*/) {
    PythonScriptController* obj = get_controller(self);
    return obj->scriptControllerInstance();
}

struct error { };

template<class T>
static inline T* operator || (T* obj, error e) {
    if(!obj) throw e;
    return obj;
}

static PyObject * PythonScriptController_new(PyTypeObject * cls, PyObject * args, PyObject* kwargs) {

    try {
        PyObject* py_node = PyTuple_GetItem(args, 0) || error();
        BaseContext* ctx = get<BaseContext>(py_node) || error();

        using controller_type = PythonScriptController;
        controller_type::SPtr controller = New<controller_type>();

        // note: original bindings **require** the controller to be wrapped as a
        // Base. virtual inheritance between Base and PythonScriptController
        // have been cleaned since then, so is should be safe to 1. wrap
        // directly as a PythonScriptController and 2. static_cast wrapped
        // pointers
        PyObject* instance = BuildPySPtr<Base>(controller.get(), cls);
        controller->setInstance(instance);

        ctx->addObject( controller );

        return instance;

    } catch (error e) {
        PyErr_SetString(PyExc_TypeError,
                        "PythonScriptController.__new__ needs a Sofa.BaseContext as first argument");
        return NULL;
    };
}

SP_CLASS_METHODS_BEGIN(PythonScriptController)
SP_CLASS_METHOD(PythonScriptController, onLoaded)
SP_CLASS_METHOD(PythonScriptController, createGraph)
SP_CLASS_METHOD(PythonScriptController, initGraph)
SP_CLASS_METHOD(PythonScriptController, bwdInitGraph)
SP_CLASS_METHOD(PythonScriptController, onKeyPressed)
SP_CLASS_METHOD(PythonScriptController, onKeyReleased)
SP_CLASS_METHOD(PythonScriptController, onMouseButtonLeft)
SP_CLASS_METHOD(PythonScriptController, onMouseButtonRight)
SP_CLASS_METHOD(PythonScriptController, onMouseButtonMiddle)
SP_CLASS_METHOD(PythonScriptController, onMouseWheel)
SP_CLASS_METHOD(PythonScriptController, onBeginAnimationStep)
SP_CLASS_METHOD(PythonScriptController, onEndAnimationStep)
SP_CLASS_METHOD(PythonScriptController, storeResetState)
SP_CLASS_METHOD(PythonScriptController, reset)
SP_CLASS_METHOD(PythonScriptController, cleanup)
SP_CLASS_METHOD(PythonScriptController, onGUIEvent)
SP_CLASS_METHOD(PythonScriptController, onScriptEvent)
SP_CLASS_METHOD(PythonScriptController, draw)
SP_CLASS_METHOD(PythonScriptController, onEvent)
SP_CLASS_METHOD(PythonScriptController, onIdle)
SP_CLASS_METHOD(PythonScriptController, instance)
SP_CLASS_METHODS_END;

static struct patch {

    patch() {
        // because i can
        SP_SOFAPYTYPEOBJECT(PythonScriptController).tp_new = PythonScriptController_new;
    }

} patcher;

SP_CLASS_TYPE_SPTR(PythonScriptController, PythonScriptController, BaseObject);
<|endoftext|>


<commit_before>//-- includes -----
#include "ServerDeviceView.h"
#include "ServerLog.h"

#include <chrono>

//-- private methods -----

//-- public implementation -----
ServerDeviceView::ServerDeviceView(
    const int device_id)
    : m_bHasUnpublishedState(false)
    , m_last_updated_tick(0)
    , m_sequence_number(0)
    , m_deviceID(device_id)
{
}

ServerDeviceView::~ServerDeviceView()
{
}

bool
ServerDeviceView::open(const DeviceEnumerator *enumerator)
{
    bool bSuccess= getDevice()->open(enumerator);

    if (bSuccess)
    {
        // Consider a successful opening as an update
        m_last_updated_tick=
        std::chrono::duration_cast< std::chrono::milliseconds >(
            std::chrono::system_clock::now().time_since_epoch()).count();
    }
    return bSuccess;
}

bool
ServerDeviceView::getIsOpen() const
{
    return getDevice()->getIsOpen();
}

bool ServerDeviceView::poll()
{
    bool bSuccessfullyUpdated= true;

    IDeviceInterface* device = getDevice();

    // Only poll data from open, bluetooth controllers
    if (device->getIsReadyToPoll())
    {
        switch (device->poll())
        {
            case IControllerInterface::_PollResultSuccessNoData:
            {
                long long now =
                std::chrono::duration_cast< std::chrono::milliseconds >(
                    std::chrono::system_clock::now().time_since_epoch()).count();
                long diff= static_cast<long>(now - m_last_updated_tick);
                long max_timeout= device->getDataTimeout();

                if (diff > max_timeout)
                {
                    SERVER_LOG_INFO("ServerControllerView::poll_open_controllers") <<
                    "Controller id " << getDeviceID() << " closing due to no data timeout (" << max_timeout << "ms)";
                    device->close();

                    bSuccessfullyUpdated= false;
                }
            }
                break;

            case IControllerInterface::_PollResultSuccessNewData:
            {
                m_last_updated_tick=
                std::chrono::duration_cast< std::chrono::milliseconds >(
                    std::chrono::system_clock::now().time_since_epoch()).count();

                // If we got new sensor data, then we have new state to publish
                markStateAsUnpublished();

                bSuccessfullyUpdated= true;
            }
                break;

            case IControllerInterface::_PollResultFailure:
            {
                SERVER_LOG_INFO("ServerControllerView::poll_open_controllers") <<
                "Controller id " << getDeviceID() << " closing due to failed read";
                device->close();

                bSuccessfullyUpdated= false;
            }
                break;
        }
    }

    return bSuccessfullyUpdated;
}

void ServerDeviceView::publish()
{
    if (m_bHasUnpublishedState)
    {
        publish_device_data_frame();

        m_bHasUnpublishedState= false;
        m_sequence_number++;
    }
}

void
ServerDeviceView::close()
{
    getDevice()->close();
}

bool
ServerDeviceView::matchesDeviceEnumerator(const DeviceEnumerator *enumerator) const
{
    return getDevice()->matchesDeviceEnumerator(enumerator);
}<commit_msg>Fixed crash in ServerDeviceView::poll() * Gracefully handle null device<commit_after>//-- includes -----
#include "ServerDeviceView.h"
#include "ServerLog.h"

#include <chrono>

//-- private methods -----

//-- public implementation -----
ServerDeviceView::ServerDeviceView(
    const int device_id)
    : m_bHasUnpublishedState(false)
    , m_last_updated_tick(0)
    , m_sequence_number(0)
    , m_deviceID(device_id)
{
}

ServerDeviceView::~ServerDeviceView()
{
}

bool
ServerDeviceView::open(const DeviceEnumerator *enumerator)
{
    bool bSuccess= getDevice()->open(enumerator);

    if (bSuccess)
    {
        // Consider a successful opening as an update
        m_last_updated_tick=
        std::chrono::duration_cast< std::chrono::milliseconds >(
            std::chrono::system_clock::now().time_since_epoch()).count();
    }
    return bSuccess;
}

bool
ServerDeviceView::getIsOpen() const
{
    return getDevice()->getIsOpen();
}

bool ServerDeviceView::poll()
{
    bool bSuccessfullyUpdated= true;

    IDeviceInterface* device = getDevice();

    // Only poll data from open, bluetooth controllers
    if (device != nullptr && device->getIsReadyToPoll())
    {
        switch (device->poll())
        {
            case IControllerInterface::_PollResultSuccessNoData:
            {
                long long now =
                std::chrono::duration_cast< std::chrono::milliseconds >(
                    std::chrono::system_clock::now().time_since_epoch()).count();
                long diff= static_cast<long>(now - m_last_updated_tick);
                long max_timeout= device->getDataTimeout();

                if (diff > max_timeout)
                {
                    SERVER_LOG_INFO("ServerControllerView::poll_open_controllers") <<
                    "Controller id " << getDeviceID() << " closing due to no data timeout (" << max_timeout << "ms)";
                    device->close();

                    bSuccessfullyUpdated= false;
                }
            }
                break;

            case IControllerInterface::_PollResultSuccessNewData:
            {
                m_last_updated_tick=
                std::chrono::duration_cast< std::chrono::milliseconds >(
                    std::chrono::system_clock::now().time_since_epoch()).count();

                // If we got new sensor data, then we have new state to publish
                markStateAsUnpublished();

                bSuccessfullyUpdated= true;
            }
                break;

            case IControllerInterface::_PollResultFailure:
            {
                SERVER_LOG_INFO("ServerControllerView::poll_open_controllers") <<
                "Controller id " << getDeviceID() << " closing due to failed read";
                device->close();

                bSuccessfullyUpdated= false;
            }
                break;
        }
    }

    return bSuccessfullyUpdated;
}

void ServerDeviceView::publish()
{
    if (m_bHasUnpublishedState)
    {
        publish_device_data_frame();

        m_bHasUnpublishedState= false;
        m_sequence_number++;
    }
}

void
ServerDeviceView::close()
{
    getDevice()->close();
}

bool
ServerDeviceView::matchesDeviceEnumerator(const DeviceEnumerator *enumerator) const
{
    return getDevice()->matchesDeviceEnumerator(enumerator);
}<|endoftext|>


<commit_before>#include "stdafx.h"
#include "envcontext_processor.h"
#include "EnVistasGeometryPlugin.h"
#include <Maplayer.h>
#include "SHP3D.h"
#include <cstring>
#include <thread>
#include "SHP3DVizPlugin.h"

using std::string;
using std::thread;

static const string shp3dRegisterName("vip_core_shpviewer");
#ifdef _DEBUG
static const string shp3dPath("E:/Vault/envision_source/x64/Debug/shp3d.dll");
#else
static const string shp3dPath("E:/Vault/envision_source/x64/Release/shp3d.dll");
#endif

static shared_ptr<VI_VizPlugin3D> LoadSHP3DDLL(const VI_Path& path) {
	if (!gPluginMgr->LoadPlugin(path)) {
		return shared_ptr<VI_VizPlugin3D>();
	}
	auto plugin = gPluginMgr->GetPluginInstance(shp3dRegisterName);
	auto shp3dPlugin = dynamic_cast<SHP3D*>(plugin);
	if (!shp3dPlugin) {
		return shared_ptr<VI_VizPlugin3D>();
	}
	return shared_ptr<VI_VizPlugin3D>(shp3dPlugin);
}

SHP3DProcessor::SHP3DProcessor(const EnvContext* context) :
	_envContext(context)
{
	context->pMapLayer->m_pMap->InstallNotifyHandler(SHP3DProcessor::OnHandlerCallback,
		(LONG_PTR)this);
	VI_Path path(shp3dPath);
	assert(path.Exists());
	_vizPlugin = LoadSHP3DDLL(path);
	_dataPlugin.reset(new EnVistasGeometryPlugin(_envContext));
	Update(_envContext);
}

int SHP3DProcessor::OnHandlerCallback(Map* map, NOTIFY_TYPE what, int a0, LONG_PTR a1,
									  LONG_PTR extra)
{
	if (what == NT_ACTIVEATTRIBUTECHANGED) {
		SHP3DProcessor* thisObject = (SHP3DProcessor*)extra;
		thisObject->Update(thisObject->_envContext);
	}
	return 1;
}

void SHP3DProcessor::Update(const EnvContext* envContext) {
	if (_envContext != envContext) {
		_envContext = envContext;
		_dataPlugin->SetEnvContext(envContext);
	}
	const int irrelevant = 0;
	_vizPlugin->SetData(_dataPlugin.get(), irrelevant);
}
<commit_msg>added some thread-safety comment<commit_after>#include "stdafx.h"
#include "envcontext_processor.h"
#include "EnVistasGeometryPlugin.h"
#include <Maplayer.h>
#include "SHP3D.h"
#include <cstring>
#include <thread>
#include "SHP3DVizPlugin.h"

using std::string;
using std::thread;

static const string shp3dRegisterName("vip_core_shpviewer");
#ifdef _DEBUG
static const string shp3dPath("E:/Vault/envision_source/x64/Debug/shp3d.dll");
#else
static const string shp3dPath("E:/Vault/envision_source/x64/Release/shp3d.dll");
#endif

static shared_ptr<VI_VizPlugin3D> LoadSHP3DDLL(const VI_Path& path) {
	if (!gPluginMgr->LoadPlugin(path)) {
		return shared_ptr<VI_VizPlugin3D>();
	}
	auto plugin = gPluginMgr->GetPluginInstance(shp3dRegisterName);
	auto shp3dPlugin = dynamic_cast<SHP3D*>(plugin);
	if (!shp3dPlugin) {
		return shared_ptr<VI_VizPlugin3D>();
	}
	return shared_ptr<VI_VizPlugin3D>(shp3dPlugin);
}

SHP3DProcessor::SHP3DProcessor(const EnvContext* context) :
	_envContext(context)
{
	context->pMapLayer->m_pMap->InstallNotifyHandler(SHP3DProcessor::OnHandlerCallback,
		(LONG_PTR)this);
	VI_Path path(shp3dPath);
	assert(path.Exists());
	_vizPlugin = LoadSHP3DDLL(path);
	_dataPlugin.reset(new EnVistasGeometryPlugin(_envContext));
	Update(_envContext);
}

int SHP3DProcessor::OnHandlerCallback(Map* map, NOTIFY_TYPE what, int a0, LONG_PTR a1,
									  LONG_PTR extra)
{
	if (what == NT_ACTIVEATTRIBUTECHANGED) {
		SHP3DProcessor* thisObject = (SHP3DProcessor*)extra;
		thisObject->Update(thisObject->_envContext);
	}
	return 1;
}

void SHP3DProcessor::Update(const EnvContext* envContext) {
	if (_envContext != envContext) {
		_envContext = envContext;
		//whoa, _dataPlugin might be in used concurrently, causing _vizPlugin
		//to produce untruthty results.
		_dataPlugin->SetEnvContext(envContext);
	}
	const int irrelevant = 0;
	_vizPlugin->SetData(_dataPlugin.get(), irrelevant);
}
<|endoftext|>


<commit_before>#include <signal.h>
#include <iostream>
#include <clocale>

#include "edn_parser.h"

#include <ruby/ruby.h>

namespace edn {

    VALUE rb_mEDNT;

    // methods on the ruby side we'll call from here
    VALUE EDNT_MAKE_SYMBOL_METHOD       = Qnil;
    VALUE EDNT_MAKE_LIST_METHOD         = Qnil;
    VALUE EDNT_MAKE_SET_METHOD          = Qnil;
    VALUE EDNT_MAKE_BIG_DECIMAL_METHOD  = Qnil;
    VALUE EDNT_TAGGED_ELEM_METHOD       = Qnil;
    VALUE EDNT_EXTENDED_VALUE_METHOD    = Qnil;

    VALUE EDNT_STRING_TO_I_METHOD       = Qnil;
    VALUE EDNT_STRING_TO_F_METHOD       = Qnil;

    // returned when EOF - defined as a constant in EDN module
    VALUE EDNT_EOF_CONST                = Qnil;

    //
    // wrappers to hook the class w/ the C-api
    template<class T>
    static void delete_obj(T *ptr) {
        delete ptr;
    }

    template<class T>
    static VALUE wrap_ptr(VALUE klass, T* ptr) {
        return Data_Wrap_Struct(klass, 0, delete_obj<T>, ptr);
    }

    static VALUE alloc_obj(VALUE self){
        return wrap_ptr<edn::Parser>(self, new Parser());
    }

    static inline Parser* get_parser(VALUE self)
    {
        Parser *p;
        Data_Get_Struct( self, edn::Parser, p );
        return p;
    }

    //
    // called by the constructor - sets the source if passed
    static VALUE initialize(int argc, VALUE* argv, VALUE self)
    {
        Parser* p = get_parser(self);

        if (argc > 0)
        {
            const char* stream = StringValueCStr(argv[0]);
            if (stream)
                p->set_source( stream, std::strlen(stream) );
        }
        return self;
    }

    //
    // change the input source
    static VALUE set_source(VALUE self, VALUE data)
    {
        Parser* p = get_parser(self);

        const char* stream = StringValueCStr(data);
        if (stream)
            p->set_source( stream, std::strlen(stream) );

        return self;
    }

    //
    // eof?
    static VALUE eof(VALUE self, VALUE data)
    {
        return get_parser(self)->is_eof();
    }

    //
    // parses an entire stream
    static VALUE read(VALUE self, VALUE data)
    {
        const char* stream = StringValueCStr(data);
        if (stream)
            return get_parser(self)->parse(stream, std::strlen(stream) );
        return Qnil;
    }

    //
    // gets the next token in the current stream
    static VALUE next(VALUE self, VALUE data)
    {
        return get_parser(self)->next();
    }

    //
    // signal handler
    static void die(int sig)
    {
        exit(-1);
    }
}

//
// ruby calls this to load the extension
extern "C"
void Init_edn_turbo(void)
{
    struct sigaction a;
    a.sa_handler = edn::die;
    sigemptyset(&a.sa_mask);
    a.sa_flags = 0;
    sigaction(SIGINT, &a, 0);

    // pass things back as utf-8
    if (!setlocale( LC_ALL, "" )) {
        std::cerr << "Error setting locale" << std::endl;
        return;
    }

    edn::rb_mEDNT = rb_define_module("EDNT");

    // bind the ruby Parser class to the C++ one
    VALUE rb_cParser = rb_define_class_under(edn::rb_mEDNT, "Parser", rb_cObject);
    rb_define_alloc_func(rb_cParser, edn::alloc_obj);
    rb_define_method(rb_cParser, "initialize", (VALUE(*)(ANYARGS)) &edn::initialize, -1 );
    rb_define_method(rb_cParser, "ext_set_stream", (VALUE(*)(ANYARGS)) &edn::set_source, 1 );
    rb_define_method(rb_cParser, "ext_eof", (VALUE(*)(ANYARGS)) &edn::eof, 0 );
    rb_define_method(rb_cParser, "ext_read", (VALUE(*)(ANYARGS)) &edn::read, 1 );
    rb_define_method(rb_cParser, "ext_next", (VALUE(*)(ANYARGS)) &edn::next, 0 );

    // bind ruby methods we'll call - these should be defined in edn_turbo.rb
    edn::EDNT_MAKE_SYMBOL_METHOD       = rb_intern("symbol");
    edn::EDNT_MAKE_LIST_METHOD         = rb_intern("list");
    edn::EDNT_MAKE_SET_METHOD          = rb_intern("set");
    edn::EDNT_MAKE_BIG_DECIMAL_METHOD  = rb_intern("big_decimal");
    edn::EDNT_TAGGED_ELEM_METHOD       = rb_intern("tagged_element");
    edn::EDNT_EXTENDED_VALUE_METHOD    = rb_intern("extend_for_meta");

    edn::EDNT_STRING_TO_I_METHOD       = rb_intern("to_i");
    edn::EDNT_STRING_TO_F_METHOD       = rb_intern("to_f");

    // so we can return EOF directly
    edn::EDNT_EOF_CONST                = rb_const_get(edn::rb_mEDNT, rb_intern("EOF"));

    // import whatever else we've defined in the ruby side
    rb_require("edn_turbo/edn_parser");
}
<commit_msg>removed unecessary include<commit_after>#include <signal.h>
#include <iostream>
#include <clocale>

#include "edn_parser.h"

#include <ruby/ruby.h>

namespace edn {

    VALUE rb_mEDNT;

    // methods on the ruby side we'll call from here
    VALUE EDNT_MAKE_SYMBOL_METHOD       = Qnil;
    VALUE EDNT_MAKE_LIST_METHOD         = Qnil;
    VALUE EDNT_MAKE_SET_METHOD          = Qnil;
    VALUE EDNT_MAKE_BIG_DECIMAL_METHOD  = Qnil;
    VALUE EDNT_TAGGED_ELEM_METHOD       = Qnil;
    VALUE EDNT_EXTENDED_VALUE_METHOD    = Qnil;

    VALUE EDNT_STRING_TO_I_METHOD       = Qnil;
    VALUE EDNT_STRING_TO_F_METHOD       = Qnil;

    // returned when EOF - defined as a constant in EDN module
    VALUE EDNT_EOF_CONST                = Qnil;

    //
    // wrappers to hook the class w/ the C-api
    template<class T>
    static void delete_obj(T *ptr) {
        delete ptr;
    }

    template<class T>
    static VALUE wrap_ptr(VALUE klass, T* ptr) {
        return Data_Wrap_Struct(klass, 0, delete_obj<T>, ptr);
    }

    static VALUE alloc_obj(VALUE self){
        return wrap_ptr<edn::Parser>(self, new Parser());
    }

    static inline Parser* get_parser(VALUE self)
    {
        Parser *p;
        Data_Get_Struct( self, edn::Parser, p );
        return p;
    }

    //
    // called by the constructor - sets the source if passed
    static VALUE initialize(int argc, VALUE* argv, VALUE self)
    {
        Parser* p = get_parser(self);

        if (argc > 0)
        {
            const char* stream = StringValueCStr(argv[0]);
            if (stream)
                p->set_source( stream, std::strlen(stream) );
        }
        return self;
    }

    //
    // change the input source
    static VALUE set_source(VALUE self, VALUE data)
    {
        Parser* p = get_parser(self);

        const char* stream = StringValueCStr(data);
        if (stream)
            p->set_source( stream, std::strlen(stream) );

        return self;
    }

    //
    // eof?
    static VALUE eof(VALUE self, VALUE data)
    {
        return get_parser(self)->is_eof();
    }

    //
    // parses an entire stream
    static VALUE read(VALUE self, VALUE data)
    {
        const char* stream = StringValueCStr(data);
        if (stream)
            return get_parser(self)->parse(stream, std::strlen(stream) );
        return Qnil;
    }

    //
    // gets the next token in the current stream
    static VALUE next(VALUE self, VALUE data)
    {
        return get_parser(self)->next();
    }

    //
    // signal handler
    static void die(int sig)
    {
        exit(-1);
    }
}

//
// ruby calls this to load the extension
extern "C"
void Init_edn_turbo(void)
{
    struct sigaction a;
    a.sa_handler = edn::die;
    sigemptyset(&a.sa_mask);
    a.sa_flags = 0;
    sigaction(SIGINT, &a, 0);

    // pass things back as utf-8
    if (!setlocale( LC_ALL, "" )) {
        std::cerr << "Error setting locale" << std::endl;
        return;
    }

    edn::rb_mEDNT = rb_define_module("EDNT");

    // bind the ruby Parser class to the C++ one
    VALUE rb_cParser = rb_define_class_under(edn::rb_mEDNT, "Parser", rb_cObject);
    rb_define_alloc_func(rb_cParser, edn::alloc_obj);
    rb_define_method(rb_cParser, "initialize", (VALUE(*)(ANYARGS)) &edn::initialize, -1 );
    rb_define_method(rb_cParser, "ext_set_stream", (VALUE(*)(ANYARGS)) &edn::set_source, 1 );
    rb_define_method(rb_cParser, "ext_eof", (VALUE(*)(ANYARGS)) &edn::eof, 0 );
    rb_define_method(rb_cParser, "ext_read", (VALUE(*)(ANYARGS)) &edn::read, 1 );
    rb_define_method(rb_cParser, "ext_next", (VALUE(*)(ANYARGS)) &edn::next, 0 );

    // bind ruby methods we'll call - these should be defined in edn_turbo.rb
    edn::EDNT_MAKE_SYMBOL_METHOD       = rb_intern("symbol");
    edn::EDNT_MAKE_LIST_METHOD         = rb_intern("list");
    edn::EDNT_MAKE_SET_METHOD          = rb_intern("set");
    edn::EDNT_MAKE_BIG_DECIMAL_METHOD  = rb_intern("big_decimal");
    edn::EDNT_TAGGED_ELEM_METHOD       = rb_intern("tagged_element");
    edn::EDNT_EXTENDED_VALUE_METHOD    = rb_intern("extend_for_meta");

    edn::EDNT_STRING_TO_I_METHOD       = rb_intern("to_i");
    edn::EDNT_STRING_TO_F_METHOD       = rb_intern("to_f");

    // so we can return EOF directly
    edn::EDNT_EOF_CONST                = rb_const_get(edn::rb_mEDNT, rb_intern("EOF"));
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <assert.h>
#include <db_cxx.h>

void hexdump(Dbt *d) {
    unsigned char *cp = (unsigned char *) d->get_data();
    int n = d->get_size();
    printf(" ");
    for (int i=0; i<n; i++)
        printf("%2.2x", cp[i]);
    printf("\n");
}

int dbdump(char *dbfile, char *dbname) {
    int r;

#if USE_ENV
    DbEnv env(DB_CXX_NO_EXCEPTIONS);
    r = env.open(".", DB_INIT_MPOOL + DB_CREATE + DB_PRIVATE, 0777); assert(r == 0);
    Db db(&env, DB_CXX_NO_EXCEPTIONS);
#else
    Db db(0, DB_CXX_NO_EXCEPTIONS);
#endif
    r = db.open(0, dbfile, dbname, DB_UNKNOWN, 0, 0777);
    if (r != 0) {
        printf("cant open %s:%s\n", dbfile, dbname);
#if USE_ENV
        r = env.close(0); assert(r == 0);
#endif
        return 1;
    }

    Dbc *cursor;
    r = db.cursor(0, &cursor, 0); assert(r == 0);

    Dbt key; key.set_flags(DB_DBT_REALLOC);
    Dbt val; val.set_flags(DB_DBT_REALLOC);
    for (;;) {
        r = cursor->get(&key, &val, DB_NEXT);
        if (r != 0) break;
        // printf("%.*s\n", key.get_size(), (char *)key.get_data());
        hexdump(&key);
        // printf("%.*s\n", val.get_size(), (char *)val.get_data());
        hexdump(&val);
    }
    if (key.get_data()) free(key.get_data());
    if (val.get_data()) free(val.get_data());

    r = cursor->close(); assert(r == 0);
    r = db.close(0); assert(r == 0);
#if USE_ENV
    r = env.close(0); assert(r == 0);
#endif
    return 0;
}

int usage() {
    printf("db_dump [-s DBNAME] DBFILE\n");
    return 1;
}

int main(int argc, char *argv[]) {
    int i;

    char *dbname = 0;
    for (i=1; i<argc; i++) {
        char *arg = argv[i];
        if (0 == strcmp(arg, "-h") || 0 == strcmp(arg, "--help"))
            return usage();
        if (0 == strcmp(arg, "-s")) {
            i++;
            if (i >= argc)
                return usage();
            dbname = argv[i];
            continue;
        }
        break;
    }

    if (i >= argc)
        return usage();
    return dbdump(argv[i], dbname);
}

<commit_msg>dump some header flags. addresses #333<commit_after>#include <stdlib.h>
#include <assert.h>
#include <db_cxx.h>

void hexdump(Dbt *d) {
    unsigned char *cp = (unsigned char *) d->get_data();
    int n = d->get_size();
    printf(" ");
    for (int i=0; i<n; i++)
        printf("%2.2x", cp[i]);
    printf("\n");
}

int dbdump(char *dbfile, char *dbname) {
    int r;

#if USE_ENV
    DbEnv env(DB_CXX_NO_EXCEPTIONS);
    r = env.open(".", DB_INIT_MPOOL + DB_CREATE + DB_PRIVATE, 0777); assert(r == 0);
    Db db(&env, DB_CXX_NO_EXCEPTIONS);
#else
    Db db(0, DB_CXX_NO_EXCEPTIONS);
#endif
    r = db.open(0, dbfile, dbname, DB_UNKNOWN, 0, 0777);
    if (r != 0) {
        printf("cant open %s:%s\n", dbfile, dbname);
#if USE_ENV
        r = env.close(0); assert(r == 0);
#endif
        return 1;
    }

    u_int32_t dbflags;
    r = db.get_flags(&dbflags); assert(r == 0);
    if (dbflags & DB_DUP)
        printf("duplicates=1\n");
    if (dbflags & DB_DUPSORT)
        printf("dupsort=1\n");
#if 0
    u_int32_t nodesize;
    r = db.get_nodesize(&nodesize); assert(r == 0);
    printf("nodesize=%d\n", nodesize);
#endif

    Dbc *cursor;
    r = db.cursor(0, &cursor, 0); assert(r == 0);

    Dbt key; key.set_flags(DB_DBT_REALLOC);
    Dbt val; val.set_flags(DB_DBT_REALLOC);
    for (;;) {
        r = cursor->get(&key, &val, DB_NEXT);
        if (r != 0) break;
        // printf("%.*s\n", key.get_size(), (char *)key.get_data());
        hexdump(&key);
        // printf("%.*s\n", val.get_size(), (char *)val.get_data());
        hexdump(&val);
    }
    if (key.get_data()) free(key.get_data());
    if (val.get_data()) free(val.get_data());

    r = cursor->close(); assert(r == 0);
    r = db.close(0); assert(r == 0);
#if USE_ENV
    r = env.close(0); assert(r == 0);
#endif
    return 0;
}

int usage() {
    printf("db_dump [-s DBNAME] DBFILE\n");
    return 1;
}

int main(int argc, char *argv[]) {
    char *dbname = 0;

    int i;
    for (i=1; i<argc; i++) {
        char *arg = argv[i];
        if (0 == strcmp(arg, "-h") || 0 == strcmp(arg, "--help"))
            return usage();
        if (0 == strcmp(arg, "-s")) {
            if (i+1 >= argc)
                return usage();
            dbname = argv[++i];
            continue;
        }
        break;
    }
    if (i >= argc)
        return usage();

    return dbdump(argv[i], dbname);
}

<|endoftext|>


<commit_before>/*
 * This file is part of QtZeitgeist.
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "QtZeitgeist/DataModel/TimeRange"

#include <limits>

namespace QtZeitgeist
{

namespace DataModel
{

class TimeRangePrivate
{
public :
    TimeRangePrivate(qint64 _begin = 0, qint64 _end = 0)
        : begin(_begin),
        end(_end)
    {
    }

    qint64 begin;
    qint64 end;
};

TimeRange::TimeRange(QObject *parent)
    : d(new TimeRangePrivate())
{
    Q_ASSERT(d);
}

TimeRange::TimeRange(const TimeRange & source, QObject *parent)
    : d(new TimeRangePrivate())
{
    Q_ASSERT(d);

    // Copy the source attribute's value.
    d->begin = source.d->begin;
    d->end = source.d->end;
}

TimeRange::TimeRange(qint64 begin, qint64 end)
    : d(new TimeRangePrivate(begin, end))
{
}

TimeRange::~TimeRange()
{
    delete d;
}

qint64 TimeRange::begin() const
{
    return d->begin;
}

void TimeRange::setBegin(qint64 begin)
{
    d->begin = begin;
}

qint64 TimeRange::end() const
{
    return d->end;
}

void TimeRange::setEnd(qint64 end)
{
    d->end = end;
}

TimeRange TimeRange::timeRangeToNow()
{
    return TimeRange(0, QDateTime::currentDateTime().toTime_t() * 1000);
}

TimeRange TimeRange::timeRangeFromNow()
{
    return TimeRange(QDateTime::currentDateTime().toTime_t() * 1000,
            std::numeric_limits<qint64>::max());
}

TimeRange TimeRange::always()
{
    return TimeRange(0, std::numeric_limits<qint64>::max());
}

TimeRange &TimeRange::operator = (const TimeRange &source)
{
    // Copy the source attribute's value.
    if (this != &source) {
        d->begin = source.d->begin;
        d->end = source.d->end;
    }

    return *this;
}

QDBusArgument & operator << (QDBusArgument &argument,
        const TimeRange &timeRange)
{
    argument.beginStructure();

    argument
        << timeRange.d->begin
        << timeRange.d->end;

    argument.endStructure();

    return argument;
}

const QDBusArgument & operator >> (const QDBusArgument &argument,
        TimeRange &timeRange)
{
    argument.beginStructure();

    argument
        >> timeRange.d->begin
        >> timeRange.d->end;

    argument.endStructure();

    return argument;
}

};

};
<commit_msg>Use toMSecsSinceEpoch() instead of toTime_t() * 1000.<commit_after>/*
 * This file is part of QtZeitgeist.
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "QtZeitgeist/DataModel/TimeRange"

#include <limits>

namespace QtZeitgeist
{

namespace DataModel
{

class TimeRangePrivate
{
public :
    TimeRangePrivate(qint64 _begin = 0, qint64 _end = 0)
        : begin(_begin),
        end(_end)
    {
    }

    qint64 begin;
    qint64 end;
};

TimeRange::TimeRange(QObject *parent)
    : d(new TimeRangePrivate())
{
    Q_ASSERT(d);
}

TimeRange::TimeRange(const TimeRange & source, QObject *parent)
    : d(new TimeRangePrivate())
{
    Q_ASSERT(d);

    // Copy the source attribute's value.
    d->begin = source.d->begin;
    d->end = source.d->end;
}

TimeRange::TimeRange(qint64 begin, qint64 end)
    : d(new TimeRangePrivate(begin, end))
{
}

TimeRange::~TimeRange()
{
    delete d;
}

qint64 TimeRange::begin() const
{
    return d->begin;
}

void TimeRange::setBegin(qint64 begin)
{
    d->begin = begin;
}

qint64 TimeRange::end() const
{
    return d->end;
}

void TimeRange::setEnd(qint64 end)
{
    d->end = end;
}

TimeRange TimeRange::timeRangeToNow()
{
    return TimeRange(0, QDateTime::currentDateTime().toMSecsSinceEpoch());
}

TimeRange TimeRange::timeRangeFromNow()
{
    return TimeRange(QDateTime::currentDateTime().toMSecsSinceEpoch(),
            std::numeric_limits<qint64>::max());
}

TimeRange TimeRange::always()
{
    return TimeRange(0, std::numeric_limits<qint64>::max());
}

TimeRange &TimeRange::operator = (const TimeRange &source)
{
    // Copy the source attribute's value.
    if (this != &source) {
        d->begin = source.d->begin;
        d->end = source.d->end;
    }

    return *this;
}

QDBusArgument & operator << (QDBusArgument &argument,
        const TimeRange &timeRange)
{
    argument.beginStructure();

    argument
        << timeRange.d->begin
        << timeRange.d->end;

    argument.endStructure();

    return argument;
}

const QDBusArgument & operator >> (const QDBusArgument &argument,
        TimeRange &timeRange)
{
    argument.beginStructure();

    argument
        >> timeRange.d->begin
        >> timeRange.d->end;

    argument.endStructure();

    return argument;
}

};

};
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *      SigmaEffect_thetadegrees                                                                  *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpeateose. It is      *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

// $Id$
//
// Class AliMUONSegmentation
// ----------------------------
// Manager class for geometry construction via geometry builders.
//
// Author: Ivana Hrivnacova, IPN Orsay

#include <iostream>

#include <TObjArray.h>

#include "AliMUONSegmentation.h"
#include "AliMUONVGeometryDESegmentation.h"
#include "AliMUONGeometrySegmentation.h"
#include "AliMUONGeometryDEIndexing.h"
#include "AliLog.h"

ClassImp(AliMUONSegmentation)

//______________________________________________________________________________
AliMUONSegmentation::AliMUONSegmentation(Int_t nofModules)
  : TObject(),
    fDESegmentations(0)
{
/// Standard constructor

  // Create array for DE segmentations
  fDESegmentations = new TObjArray();
  fDESegmentations->SetOwner(kTRUE);

  // Create array for modules segmentations
  for (Int_t cathod = 0; cathod < 2; cathod++) {
    fModuleSegmentations[cathod] = new TObjArray(nofModules);
    fModuleSegmentations[cathod]->SetOwner(true);

    for (Int_t i=0; i<nofModules; i++)
      fModuleSegmentations[cathod]->AddAt(0, i);
  }

  AliDebug(1, Form("ctor this = %p", this) );
}

//______________________________________________________________________________
AliMUONSegmentation::AliMUONSegmentation()
  : TObject(),
    fDESegmentations(0)
{
/// Default constructor

  fModuleSegmentations[0] = 0;
  fModuleSegmentations[1] = 0;

  AliDebug(1, Form("default (empty) ctor this = %p", this));
}

//______________________________________________________________________________
AliMUONSegmentation::AliMUONSegmentation(const AliMUONSegmentation& right)
  : TObject(right)
{
/// Copy constructor (not implemented)

  AliFatal("Copy constructor not provided.");
}

//______________________________________________________________________________
AliMUONSegmentation::~AliMUONSegmentation()
{
/// Destructor

  AliDebug(1, Form("dtor this = %p", this));

  delete fDESegmentations;
  delete fModuleSegmentations[0];
  delete fModuleSegmentations[1];
}

//______________________________________________________________________________
AliMUONSegmentation&
AliMUONSegmentation::operator=(const AliMUONSegmentation& right)
{
/// Assignement operator (not implemented)

  // check assignement to self
  if (this == &right) return *this;

  AliFatal("Assignement operator not provided.");

  return *this;
}

//
// public functions
//

//_____________________________________________________________________________
void AliMUONSegmentation::AddDESegmentation(
                             AliMUONVGeometryDESegmentation* segmentation)
{
/// Add the DE segmentation to the array

  fDESegmentations->Add(segmentation);
}

//_____________________________________________________________________________
void AliMUONSegmentation::AddModuleSegmentation(Int_t moduleId, Int_t cathod,
                             AliMUONGeometrySegmentation* segmentation)
{
/// Add the module segmentation to the array

  if (cathod < 0 || cathod >= 2) {
      AliErrorStream()
        << "Cathod: " << cathod << " outside limits" << std::endl;
      return;
  }

  if (moduleId < 0 || moduleId >= fModuleSegmentations[cathod]->GetEntriesFast()) {
    AliErrorStream()
        << "Module Id: " << moduleId << " outside limits" << std::endl;
    return;
  }

  fModuleSegmentations[cathod]->AddAt(segmentation, moduleId);
}

//_____________________________________________________________________________
void  AliMUONSegmentation::Init()
{
/// Initialize all segmentations

  for (Int_t cathod = 0; cathod < 2; cathod++) {
    for (Int_t i = 0; i < fModuleSegmentations[cathod]->GetEntriesFast(); i++) {

      AliMUONGeometrySegmentation* moduleSegmentation
        = (AliMUONGeometrySegmentation*)fModuleSegmentations[cathod]->At(i);

      if (moduleSegmentation) moduleSegmentation->Init(i);
    }
  }
}

//_____________________________________________________________________________
AliMUONGeometrySegmentation*
AliMUONSegmentation::GetModuleSegmentation(
                        Int_t moduleId, Int_t cathod, Bool_t warn) const
{
/// Return the geometry module specified by moduleId

  if (cathod < 0 || cathod >= 2) {
    if (warn) {
      AliWarningStream()
        << "Cathod: " << cathod << " outside limits" << std::endl;
    }
    return 0;
  }

  if (moduleId < 0 || moduleId >= fModuleSegmentations[cathod]->GetEntriesFast()) {
    if (warn) {
      AliWarningStream()
        << "Index: " << moduleId << " outside limits" << std::endl;
    }
    return 0;
  }

  return (AliMUONGeometrySegmentation*)
            fModuleSegmentations[cathod]->At(moduleId);
}

//_____________________________________________________________________________
AliMUONGeometrySegmentation*
AliMUONSegmentation::GetModuleSegmentationByDEId(
                        Int_t detElemId, Int_t cathod, Bool_t warn) const
{
/// Return the geometry module specified by detElemId/cathod

  // Get moduleId
  Int_t moduleId = AliMUONGeometryDEIndexing::GetModuleId(detElemId);

  return GetModuleSegmentation(moduleId, cathod, warn);
}

//_____________________________________________________________________________
const AliMUONVGeometryDESegmentation*
AliMUONSegmentation::GetDESegmentation(
                        Int_t detElemId, Int_t cathod, Bool_t warn) const
{
/// Return the DE segmentation specified by detElemId/cathod

  // Get geometry segmentation
  AliMUONGeometrySegmentation* moduleSegmentation
    = GetModuleSegmentationByDEId(detElemId, cathod, warn);

  if ( !moduleSegmentation ) return 0;

  return moduleSegmentation->GetDESegmentation(detElemId, warn);
}

//_____________________________________________________________________________
const AliMpVSegmentation*
AliMUONSegmentation::GetMpSegmentation(
                     Int_t detElemId, Int_t cathod, Bool_t warn) const
{
/// Return the mapping segmentation specified by detElemId/cathod

  // Get DE segmentation
  const AliMUONVGeometryDESegmentation* kdeSegmentation
    = GetDESegmentation(detElemId, cathod, warn);

  if ( !kdeSegmentation ) return 0;

  return kdeSegmentation->GetMpSegmentation();
}

//_____________________________________________________________________________
Bool_t
AliMUONSegmentation::HasDE(Int_t detElemId, Int_t cathod) const
{
  // Get DE segmentation
  const AliMUONVGeometryDESegmentation* kdeSegmentation
    = GetDESegmentation(detElemId, cathod, false);

  return ( kdeSegmentation != 0 );

}

//_____________________________________________________________________________
TString
AliMUONSegmentation::GetDEName(Int_t detElemId, Int_t cathod) const
{

  // Get geometry segmentation
  AliMUONGeometrySegmentation* moduleSegmentation
    = GetModuleSegmentationByDEId(detElemId, cathod, true);

  return  moduleSegmentation->GetDEName(detElemId);
}

<commit_msg>- Added fMpSegmentations data member (used for deleting mapping segmentations   not included in DE segmentations) - Using AliMUONGeometryStore instead of AliMUONGeometryDEIndexing   (now removed)<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *      SigmaEffect_thetadegrees                                                                  *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpeateose. It is      *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

// $Id$
//
// Class AliMUONSegmentation
// ----------------------------
// Manager class for geometry construction via geometry builders.
//
// Author: Ivana Hrivnacova, IPN Orsay

#include <iostream>

#include <TObjArray.h>

#include "AliMUONSegmentation.h"
#include "AliMUONVGeometryDESegmentation.h"
#include "AliMUONGeometrySegmentation.h"
#include "AliMUONGeometryStore.h"

#include "AliMpVSegmentation.h"

#include "AliLog.h"

ClassImp(AliMUONSegmentation)

//______________________________________________________________________________
AliMUONSegmentation::AliMUONSegmentation(Int_t nofModules)
  : TObject(),
    fMpSegmentations(0),
    fDESegmentations(0)
{
/// Standard constructor

  // Create array for mapping segmentations
  fMpSegmentations = new TObjArray();
  fMpSegmentations->SetOwner(kTRUE);

  // Create array for DE segmentations
  fDESegmentations = new TObjArray();
  fDESegmentations->SetOwner(kTRUE);

  // Create array for modules segmentations
  for (Int_t cathod = 0; cathod < 2; cathod++) {
    fModuleSegmentations[cathod] = new TObjArray(nofModules);
    fModuleSegmentations[cathod]->SetOwner(true);

    for (Int_t i=0; i<nofModules; i++)
      fModuleSegmentations[cathod]->AddAt(0, i);
  }

  AliDebug(1, Form("ctor this = %p", this) );
}

//______________________________________________________________________________
AliMUONSegmentation::AliMUONSegmentation()
  : TObject(),
    fMpSegmentations(0),
    fDESegmentations(0)
{
/// Default constructor

  fModuleSegmentations[0] = 0;
  fModuleSegmentations[1] = 0;

  AliDebug(1, Form("default (empty) ctor this = %p", this));
}

//______________________________________________________________________________
AliMUONSegmentation::AliMUONSegmentation(const AliMUONSegmentation& right)
  : TObject(right)
{
/// Copy constructor (not implemented)

  AliFatal("Copy constructor not provided.");
}

//______________________________________________________________________________
AliMUONSegmentation::~AliMUONSegmentation()
{
/// Destructor

  AliDebug(1, Form("dtor this = %p", this));

  delete fMpSegmentations;
  delete fDESegmentations;
  delete fModuleSegmentations[0];
  delete fModuleSegmentations[1];
}

//______________________________________________________________________________
AliMUONSegmentation&
AliMUONSegmentation::operator=(const AliMUONSegmentation& right)
{
/// Assignement operator (not implemented)

  // check assignement to self
  if (this == &right) return *this;

  AliFatal("Assignement operator not provided.");

  return *this;
}

//
// public functions
//

//_____________________________________________________________________________
void AliMUONSegmentation::AddMpSegmentation(AliMpVSegmentation* segmentation)
{
/// Add the mapping segmentation to the array if not present

  Bool_t isPresent = false;
  for (Int_t i=0; i<fMpSegmentations->GetEntries(); i++)
    if ( (AliMpVSegmentation*)fMpSegmentations->At(i) == segmentation ) {
      isPresent = true;
      break;
    }

  if (!isPresent) fMpSegmentations->Add(segmentation);
}

//_____________________________________________________________________________
void AliMUONSegmentation::AddDESegmentation(
                                AliMUONVGeometryDESegmentation* segmentation)
{
/// Add the DE segmentation to the array

  fDESegmentations->Add(segmentation);

  // Deregister the mapping segmentation contained in DE segmentation
  // from fMpSegmentations, if present
  const AliMpVSegmentation* kmpSeg = segmentation->GetMpSegmentation();

  for (Int_t i=0; i<fMpSegmentations->GetEntries(); i++)
    if ( (const AliMpVSegmentation*)fMpSegmentations->At(i) == kmpSeg ) {
      fMpSegmentations->RemoveAt(i);
      break;
    }
}

//_____________________________________________________________________________
void AliMUONSegmentation::AddModuleSegmentation(Int_t moduleId, Int_t cathod,
                             AliMUONGeometrySegmentation* segmentation)
{
/// Add the module segmentation to the array

  if (cathod < 0 || cathod >= 2) {
      AliErrorStream()
        << "Cathod: " << cathod << " outside limits" << std::endl;
      return;
  }

  if (moduleId < 0 || moduleId >= fModuleSegmentations[cathod]->GetEntriesFast()) {
    AliErrorStream()
        << "Module Id: " << moduleId << " outside limits" << std::endl;
    return;
  }

  fModuleSegmentations[cathod]->AddAt(segmentation, moduleId);
}

//_____________________________________________________________________________
void  AliMUONSegmentation::Init()
{
/// Initialize all segmentations

  for (Int_t cathod = 0; cathod < 2; cathod++) {
    for (Int_t i = 0; i < fModuleSegmentations[cathod]->GetEntriesFast(); i++) {

      AliMUONGeometrySegmentation* moduleSegmentation
        = (AliMUONGeometrySegmentation*)fModuleSegmentations[cathod]->At(i);

      if (moduleSegmentation) moduleSegmentation->Init(i);
    }
  }
}

//_____________________________________________________________________________
AliMUONGeometrySegmentation*
AliMUONSegmentation::GetModuleSegmentation(
                        Int_t moduleId, Int_t cathod, Bool_t warn) const
{
/// Return the geometry module specified by moduleId

  if (cathod < 0 || cathod >= 2) {
    if (warn) {
      AliWarningStream()
        << "Cathod: " << cathod << " outside limits" << std::endl;
    }
    return 0;
  }

  if (moduleId < 0 || moduleId >= fModuleSegmentations[cathod]->GetEntriesFast()) {
    if (warn) {
      AliWarningStream()
        << "Index: " << moduleId << " outside limits" << std::endl;
    }
    return 0;
  }

  return (AliMUONGeometrySegmentation*)
            fModuleSegmentations[cathod]->At(moduleId);
}

//_____________________________________________________________________________
AliMUONGeometrySegmentation*
AliMUONSegmentation::GetModuleSegmentationByDEId(
                        Int_t detElemId, Int_t cathod, Bool_t warn) const
{
/// Return the geometry module specified by detElemId/cathod

  // Get moduleId
  Int_t moduleId = AliMUONGeometryStore::GetModuleId(detElemId);

  return GetModuleSegmentation(moduleId, cathod, warn);
}

//_____________________________________________________________________________
const AliMUONVGeometryDESegmentation*
AliMUONSegmentation::GetDESegmentation(
                        Int_t detElemId, Int_t cathod, Bool_t warn) const
{
/// Return the DE segmentation specified by detElemId/cathod

  // Get geometry segmentation
  AliMUONGeometrySegmentation* moduleSegmentation
    = GetModuleSegmentationByDEId(detElemId, cathod, warn);

  if ( !moduleSegmentation ) return 0;

  return moduleSegmentation->GetDESegmentation(detElemId, warn);
}

//_____________________________________________________________________________
const AliMpVSegmentation*
AliMUONSegmentation::GetMpSegmentation(
                     Int_t detElemId, Int_t cathod, Bool_t warn) const
{
/// Return the mapping segmentation specified by detElemId/cathod

  // Get DE segmentation
  const AliMUONVGeometryDESegmentation* kdeSegmentation
    = GetDESegmentation(detElemId, cathod, warn);

  if ( !kdeSegmentation ) return 0;

  return kdeSegmentation->GetMpSegmentation();
}

//_____________________________________________________________________________
Bool_t
AliMUONSegmentation::HasDE(Int_t detElemId, Int_t cathod) const
{
  // Get DE segmentation
  const AliMUONVGeometryDESegmentation* kdeSegmentation
    = GetDESegmentation(detElemId, cathod, false);

  return ( kdeSegmentation != 0 );

}

//_____________________________________________________________________________
TString
AliMUONSegmentation::GetDEName(Int_t detElemId, Int_t cathod) const
{

  // Get geometry segmentation
  AliMUONGeometrySegmentation* moduleSegmentation
    = GetModuleSegmentationByDEId(detElemId, cathod, true);

  return  moduleSegmentation->GetDEName(detElemId);
}

<|endoftext|>


<commit_before>//
//  Dave.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 22/06/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#include "Dave.hpp"

using namespace Enterprise::Dave;

// MARK: - Audio generator

Audio::Audio(Concurrency::DeferringAsyncTaskQueue &audio_queue) :
	audio_queue_(audio_queue) {}

void Audio::write(uint16_t address, uint8_t value) {
	address &= 0xf;
	audio_queue_.defer([address, value, this] {
		switch(address) {
			case 0:	case 2:	case 4:
				channels_[address >> 1].reload = (channels_[address >> 1].reload & 0xff00) | value;
			break;
			case 1:	case 3:	case 5:
				channels_[address >> 1].reload = uint16_t((channels_[address >> 1].reload & 0x00ff) | ((value & 0xf) << 8));
				channels_[address >> 1].distortion = Channel::Distortion((value >> 4)&3);
				channels_[address >> 1].high_pass = value & 0x40;
				channels_[address >> 1].ring_modulate = value & 0x80;
			break;
			case 6:
				noise_.frequency = Noise::Frequency(value&3);
				noise_.polynomial = Noise::Polynomial((value >> 2)&3);
				noise_.swap_polynomial = value & 0x10;
				noise_.low_pass = value & 0x20;
				noise_.high_pass = value & 0x40;
				noise_.ring_modulate = value & 0x80;
			break;

			case 7:
				channels_[0].sync = value & 0x01;
				channels_[1].sync = value & 0x02;
				channels_[2].sync = value & 0x04;
				use_direct_output_[0] = value & 0x08;
				use_direct_output_[1] = value & 0x10;
				// Interrupt bits are handled separately.
			break;

			case 8: case 9: case 10:
				channels_[address - 8].amplitude[0] = value & 0x3f;
			break;
			case 12: case 13: case 14:
				channels_[address - 12].amplitude[1] = value & 0x3f;
			break;
			case 11:	noise_.amplitude[0] = value & 0x3f;		break;
			case 15:	noise_.amplitude[1] = value & 0x3f;		break;
		}
	});
}

void Audio::set_sample_volume_range(int16_t range) {
	audio_queue_.defer([range, this] {
		volume_ = range / (63*4);
	});
}

void Audio::update_channel(int c) {
	if(channels_[c].sync) {
		channels_[c].count = channels_[c].reload;
		channels_[c].output <<= 1;
		return;
	}

	auto output = channels_[c].output & 1;
	channels_[c].output <<= 1;
	if(!channels_[c].count) {
		channels_[c].count = channels_[c].reload;

		if(channels_[c].distortion == Channel::Distortion::None)
			output ^= 1;
		else
			output = poly_state_[int(channels_[c].distortion)];

		if(channels_[c].high_pass && (channels_[(c+1)%3].output&3) == 2) {
			output = 0;
		}
		if(channels_[c].ring_modulate) {
			output = ~(output ^ channels_[(c+2)%3].output) & 1;
		}
	} else {
		--channels_[c].count;
	}

	channels_[c].output |= output;
}

void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
	for(size_t c = 0; c < number_of_samples; c++) {
		poly_state_[int(Channel::Distortion::FourBit)] = poly4_.next();
		poly_state_[int(Channel::Distortion::FiveBit)] = poly5_.next();
		poly_state_[int(Channel::Distortion::SevenBit)] = poly7_.next();
		if(noise_.swap_polynomial) {
			poly_state_[int(Channel::Distortion::SevenBit)] = poly_state_[int(Channel::Distortion::None)];
		}

		// Update tone channels.
		update_channel(0);
		update_channel(1);
		update_channel(2);

		// Update noise channel.

		// Step 1: decide whether there is a tick to apply.
		bool noise_tick = false;
		if(noise_.frequency == Noise::Frequency::DivideByFour) {
			if(!noise_.count) {
				noise_tick = true;
				noise_.count = 3;
			} else {
				--noise_.count;
			}
		} else {
			noise_tick = (channels_[int(noise_.frequency) - 1].output&3) == 2;
		}

		// Step 2: tick if necessary.
		int noise_output = noise_.output & 1;
		noise_.output <<= 1;
		if(noise_tick) {
			switch(noise_.polynomial) {
				case Noise::Polynomial::SeventeenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly17_.next());
				break;
				case Noise::Polynomial::FifteenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly15_.next());
				break;
				case Noise::Polynomial::ElevenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly11_.next());
				break;
				case Noise::Polynomial::NineBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly9_.next());
				break;
			}

			noise_output = poly_state_[int(Channel::Distortion::None)];
		}
		noise_.output |= noise_output;

		// Low pass: sample channel 2 on downward transitions of the prima facie output.
		if(noise_.low_pass && (noise_.output & 3) == 2) {
			noise_.output = (noise_.output & ~1) | (channels_[2].output & 1);
		}

		// Apply noise high-pass.
		if(noise_.high_pass && (channels_[0].output & 3) == 2) {
			noise_.output &= ~1;
		}

		// Update noise ring modulation, if any.
		if(noise_.ring_modulate) {
			noise_.final_output = !((noise_.output ^ channels_[1].output) & 1);
		} else {
			noise_.final_output = noise_.output & 1;
		}

		// I'm unclear on the details of the time division multiplexing so,
		// for now, just sum the outputs.
		target[(c << 1) + 0] =
			volume_ *
				(use_direct_output_[0] ?
					channels_[0].amplitude[0]
					: (
						channels_[0].amplitude[0] * (channels_[0].output & 1) +
						channels_[1].amplitude[0] * (channels_[1].output & 1) +
						channels_[2].amplitude[0] * (channels_[2].output & 1) +
						noise_.amplitude[0] * noise_.final_output
				));

		target[(c << 1) + 1] =
			volume_ *
				(use_direct_output_[1] ?
					channels_[0].amplitude[1]
					: (
						channels_[0].amplitude[1] * (channels_[0].output & 1) +
						channels_[1].amplitude[1] * (channels_[1].output & 1) +
						channels_[2].amplitude[1] * (channels_[2].output & 1) +
						noise_.amplitude[1] * noise_.final_output
				));
	}
}

// MARK: - Interrupt source

uint8_t TimedInterruptSource::get_new_interrupts() {
	const uint8_t result = interrupts_;
	interrupts_ = 0;
	return result;
}

void TimedInterruptSource::write(uint16_t address, uint8_t value) {
	address &= 15;
	switch(address) {
		default: break;

		case 0: case 2:
			channels_[address >> 1].reload = (channels_[address >> 1].reload & 0xff00) | value;
		break;
		case 1:	case 3:
			channels_[address >> 1].reload = uint16_t((channels_[address >> 1].reload & 0x00ff) | ((value & 0xf) << 8));
		break;

		case 7: {
			channels_[0].sync = value & 0x01;
			channels_[1].sync = value & 0x02;

			const InterruptRate rate = InterruptRate((value >> 5) & 3);
			if(rate != rate_) {
				rate_ = rate;

				if(rate_ >= InterruptRate::ToneGenerator0) {
					programmable_level_ = channels_[int(rate_) - int(InterruptRate::ToneGenerator0)].level;
				} else {
					programmable_offset_ = programmble_reload(rate_);
				}
			}
		} break;
	}
}

void TimedInterruptSource::update_channel(int c, bool is_linked, int decrement) {
	if(channels_[c].sync) {
		channels_[c].value = channels_[c].reload;
	} else {
		if(decrement <= channels_[c].value) {
			channels_[c].value -= decrement;
		} else {
			// The decrement is greater than the current value, therefore
			// there'll be at least one flip.
			//
			// After decreasing the decrement by the current value + 1,
			// it'll be clear how many decrements are left after reload.
			//
			// Dividing that by the number of decrements necessary for a
			// flip will provide the total number of flips.
			const int decrements_after_flip = decrement - (channels_[c].value + 1);
			const int num_flips = 1 + decrements_after_flip / (channels_[c].reload + 1);

			// If this is a linked channel, set the interrupt mask if a transition
			// from high to low is amongst the included flips.
			if(is_linked && num_flips + channels_[c].level >= 2) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
			}
			channels_[c].level ^= (num_flips & 1);

			// Apply the modulo number of decrements to the reload value to
			// figure out where things stand now.
			channels_[c].value = channels_[c].reload - decrements_after_flip % (channels_[c].reload + 1);
		}
	}
}

void TimedInterruptSource::run_for(Cycles cycles) {
	// Update the 1Hz interrupt.
	one_hz_offset_ -= cycles;
	if(one_hz_offset_ <= Cycles(0)) {
		interrupts_ |= uint8_t(Interrupt::OneHz);
		one_hz_offset_ += clock_rate;
	}

	// Update the two tone channels.
	update_channel(0, rate_ == InterruptRate::ToneGenerator0, cycles.as<int>());
	update_channel(1, rate_ == InterruptRate::ToneGenerator1, cycles.as<int>());

	// Update the programmable-frequency interrupt.
	if(rate_ < InterruptRate::ToneGenerator0) {
		programmable_offset_ -= cycles.as<int>();
		if(programmable_offset_ <= 0) {
			if(programmable_level_) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
			}
			programmable_level_ ^= true;
			programmable_offset_ = programmble_reload(rate_);
		}
	}
}

Cycles TimedInterruptSource::get_next_sequence_point() const {
	int result = one_hz_offset_.as<int>();

	switch(rate_) {
		case InterruptRate::OnekHz:
		case InterruptRate::FiftyHz:
			result = std::min(result, programmable_offset_ + (!programmable_level_)*programmble_reload(rate_));
		break;
		case InterruptRate::ToneGenerator0:
		case InterruptRate::ToneGenerator1: {
			const auto &channel = channels_[int(rate_) - int(InterruptRate::ToneGenerator0)];
			const int cycles_until_interrupt = channel.value + 1 + (channel.level ? 0 : channel.reload + 1);
			result = std::min(result, cycles_until_interrupt);
		} break;
	}

	return Cycles(result);
}

uint8_t TimedInterruptSource::get_divider_state() {
	bool programmable_flag = false;
	switch(rate_) {
		case InterruptRate::OnekHz:
		case InterruptRate::FiftyHz:
			programmable_flag = programmable_level_;
		break;
		case InterruptRate::ToneGenerator0:
			programmable_flag = channels_[0].level;
		break;
		case InterruptRate::ToneGenerator1:
			programmable_flag = channels_[1].level;
		break;
	}

	// one_hz_offset_ counts downwards, so when it crosses the halfway mark
	// it enters the high part of its wave.
	return
		(one_hz_offset_ < half_clock_rate ? 0x4 : 0x0) |
		(programmable_flag ? 0x1 : 0x0);
}
<commit_msg>Be consistent in expression of logic.<commit_after>//
//  Dave.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 22/06/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#include "Dave.hpp"

using namespace Enterprise::Dave;

// MARK: - Audio generator

Audio::Audio(Concurrency::DeferringAsyncTaskQueue &audio_queue) :
	audio_queue_(audio_queue) {}

void Audio::write(uint16_t address, uint8_t value) {
	address &= 0xf;
	audio_queue_.defer([address, value, this] {
		switch(address) {
			case 0:	case 2:	case 4:
				channels_[address >> 1].reload = (channels_[address >> 1].reload & 0xff00) | value;
			break;
			case 1:	case 3:	case 5:
				channels_[address >> 1].reload = uint16_t((channels_[address >> 1].reload & 0x00ff) | ((value & 0xf) << 8));
				channels_[address >> 1].distortion = Channel::Distortion((value >> 4)&3);
				channels_[address >> 1].high_pass = value & 0x40;
				channels_[address >> 1].ring_modulate = value & 0x80;
			break;
			case 6:
				noise_.frequency = Noise::Frequency(value&3);
				noise_.polynomial = Noise::Polynomial((value >> 2)&3);
				noise_.swap_polynomial = value & 0x10;
				noise_.low_pass = value & 0x20;
				noise_.high_pass = value & 0x40;
				noise_.ring_modulate = value & 0x80;
			break;

			case 7:
				channels_[0].sync = value & 0x01;
				channels_[1].sync = value & 0x02;
				channels_[2].sync = value & 0x04;
				use_direct_output_[0] = value & 0x08;
				use_direct_output_[1] = value & 0x10;
				// Interrupt bits are handled separately.
			break;

			case 8: case 9: case 10:
				channels_[address - 8].amplitude[0] = value & 0x3f;
			break;
			case 12: case 13: case 14:
				channels_[address - 12].amplitude[1] = value & 0x3f;
			break;
			case 11:	noise_.amplitude[0] = value & 0x3f;		break;
			case 15:	noise_.amplitude[1] = value & 0x3f;		break;
		}
	});
}

void Audio::set_sample_volume_range(int16_t range) {
	audio_queue_.defer([range, this] {
		volume_ = range / (63*4);
	});
}

void Audio::update_channel(int c) {
	if(channels_[c].sync) {
		channels_[c].count = channels_[c].reload;
		channels_[c].output <<= 1;
		return;
	}

	auto output = channels_[c].output & 1;
	channels_[c].output <<= 1;
	if(!channels_[c].count) {
		channels_[c].count = channels_[c].reload;

		if(channels_[c].distortion == Channel::Distortion::None)
			output ^= 1;
		else
			output = poly_state_[int(channels_[c].distortion)];

		if(channels_[c].high_pass && (channels_[(c+1)%3].output&3) == 2) {
			output = 0;
		}
		if(channels_[c].ring_modulate) {
			output = ~(output ^ channels_[(c+2)%3].output) & 1;
		}
	} else {
		--channels_[c].count;
	}

	channels_[c].output |= output;
}

void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
	for(size_t c = 0; c < number_of_samples; c++) {
		poly_state_[int(Channel::Distortion::FourBit)] = poly4_.next();
		poly_state_[int(Channel::Distortion::FiveBit)] = poly5_.next();
		poly_state_[int(Channel::Distortion::SevenBit)] = poly7_.next();
		if(noise_.swap_polynomial) {
			poly_state_[int(Channel::Distortion::SevenBit)] = poly_state_[int(Channel::Distortion::None)];
		}

		// Update tone channels.
		update_channel(0);
		update_channel(1);
		update_channel(2);

		// Update noise channel.

		// Step 1: decide whether there is a tick to apply.
		bool noise_tick = false;
		if(noise_.frequency == Noise::Frequency::DivideByFour) {
			if(!noise_.count) {
				noise_tick = true;
				noise_.count = 3;
			} else {
				--noise_.count;
			}
		} else {
			noise_tick = (channels_[int(noise_.frequency) - 1].output&3) == 2;
		}

		// Step 2: tick if necessary.
		int noise_output = noise_.output & 1;
		noise_.output <<= 1;
		if(noise_tick) {
			switch(noise_.polynomial) {
				case Noise::Polynomial::SeventeenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly17_.next());
				break;
				case Noise::Polynomial::FifteenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly15_.next());
				break;
				case Noise::Polynomial::ElevenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly11_.next());
				break;
				case Noise::Polynomial::NineBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly9_.next());
				break;
			}

			noise_output = poly_state_[int(Channel::Distortion::None)];
		}
		noise_.output |= noise_output;

		// Low pass: sample channel 2 on downward transitions of the prima facie output.
		if(noise_.low_pass && (noise_.output & 3) == 2) {
			noise_.output = (noise_.output & ~1) | (channels_[2].output & 1);
		}

		// Apply noise high-pass.
		if(noise_.high_pass && (channels_[0].output & 3) == 2) {
			noise_.output &= ~1;
		}

		// Update noise ring modulation, if any.
		if(noise_.ring_modulate) {
			noise_.final_output = !((noise_.output ^ channels_[1].output) & 1);
		} else {
			noise_.final_output = noise_.output & 1;
		}

		// I'm unclear on the details of the time division multiplexing so,
		// for now, just sum the outputs.
		target[(c << 1) + 0] =
			volume_ *
				(use_direct_output_[0] ?
					channels_[0].amplitude[0]
					: (
						channels_[0].amplitude[0] * (channels_[0].output & 1) +
						channels_[1].amplitude[0] * (channels_[1].output & 1) +
						channels_[2].amplitude[0] * (channels_[2].output & 1) +
						noise_.amplitude[0] * noise_.final_output
				));

		target[(c << 1) + 1] =
			volume_ *
				(use_direct_output_[1] ?
					channels_[0].amplitude[1]
					: (
						channels_[0].amplitude[1] * (channels_[0].output & 1) +
						channels_[1].amplitude[1] * (channels_[1].output & 1) +
						channels_[2].amplitude[1] * (channels_[2].output & 1) +
						noise_.amplitude[1] * noise_.final_output
				));
	}
}

// MARK: - Interrupt source

uint8_t TimedInterruptSource::get_new_interrupts() {
	const uint8_t result = interrupts_;
	interrupts_ = 0;
	return result;
}

void TimedInterruptSource::write(uint16_t address, uint8_t value) {
	address &= 15;
	switch(address) {
		default: break;

		case 0: case 2:
			channels_[address >> 1].reload = (channels_[address >> 1].reload & 0xff00) | value;
		break;
		case 1:	case 3:
			channels_[address >> 1].reload = uint16_t((channels_[address >> 1].reload & 0x00ff) | ((value & 0xf) << 8));
		break;

		case 7: {
			channels_[0].sync = value & 0x01;
			channels_[1].sync = value & 0x02;

			const InterruptRate rate = InterruptRate((value >> 5) & 3);
			if(rate != rate_) {
				rate_ = rate;

				if(rate_ >= InterruptRate::ToneGenerator0) {
					programmable_level_ = channels_[int(rate_) - int(InterruptRate::ToneGenerator0)].level;
				} else {
					programmable_offset_ = programmble_reload(rate_);
				}
			}
		} break;
	}
}

void TimedInterruptSource::update_channel(int c, bool is_linked, int decrement) {
	if(channels_[c].sync) {
		channels_[c].value = channels_[c].reload;
	} else {
		if(decrement <= channels_[c].value) {
			channels_[c].value -= decrement;
		} else {
			// The decrement is greater than the current value, therefore
			// there'll be at least one flip.
			//
			// After decreasing the decrement by the current value + 1,
			// it'll be clear how many decrements are left after reload.
			//
			// Dividing that by the number of decrements necessary for a
			// flip will provide the total number of flips.
			const int decrements_after_flip = decrement - (channels_[c].value + 1);
			const int num_flips = 1 + decrements_after_flip / (channels_[c].reload + 1);

			// If this is a linked channel, set the interrupt mask if a transition
			// from high to low is amongst the included flips.
			if(is_linked && num_flips + channels_[c].level >= 2) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
			}
			channels_[c].level ^= (num_flips & 1);

			// Apply the modulo number of decrements to the reload value to
			// figure out where things stand now.
			channels_[c].value = channels_[c].reload - decrements_after_flip % (channels_[c].reload + 1);
		}
	}
}

void TimedInterruptSource::run_for(Cycles cycles) {
	// Update the 1Hz interrupt.
	one_hz_offset_ -= cycles;
	if(one_hz_offset_ <= Cycles(0)) {
		interrupts_ |= uint8_t(Interrupt::OneHz);
		one_hz_offset_ += clock_rate;
	}

	// Update the two tone channels.
	update_channel(0, rate_ == InterruptRate::ToneGenerator0, cycles.as<int>());
	update_channel(1, rate_ == InterruptRate::ToneGenerator1, cycles.as<int>());

	// Update the programmable-frequency interrupt.
	if(rate_ < InterruptRate::ToneGenerator0) {
		programmable_offset_ -= cycles.as<int>();
		if(programmable_offset_ <= 0) {
			if(programmable_level_) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
			}
			programmable_level_ ^= true;
			programmable_offset_ = programmble_reload(rate_);
		}
	}
}

Cycles TimedInterruptSource::get_next_sequence_point() const {
	int result = one_hz_offset_.as<int>();

	switch(rate_) {
		case InterruptRate::OnekHz:
		case InterruptRate::FiftyHz:
			result = std::min(result, programmable_offset_ + (!programmable_level_) * programmble_reload(rate_));
		break;
		case InterruptRate::ToneGenerator0:
		case InterruptRate::ToneGenerator1: {
			const auto &channel = channels_[int(rate_) - int(InterruptRate::ToneGenerator0)];
			const int cycles_until_interrupt = channel.value + 1 + (!channel.level) * (channel.reload + 1);
			result = std::min(result, cycles_until_interrupt);
		} break;
	}

	return Cycles(result);
}

uint8_t TimedInterruptSource::get_divider_state() {
	bool programmable_flag = false;
	switch(rate_) {
		case InterruptRate::OnekHz:
		case InterruptRate::FiftyHz:
			programmable_flag = programmable_level_;
		break;
		case InterruptRate::ToneGenerator0:
			programmable_flag = channels_[0].level;
		break;
		case InterruptRate::ToneGenerator1:
			programmable_flag = channels_[1].level;
		break;
	}

	// one_hz_offset_ counts downwards, so when it crosses the halfway mark
	// it enters the high part of its wave.
	return
		(one_hz_offset_ < half_clock_rate ? 0x4 : 0x0) |
		(programmable_flag ? 0x1 : 0x0);
}
<|endoftext|>