<commit_before>/*
** See Copyright Notice in LICENSE.
**/
#include "luno.hxx"

#include <cppuhelper/typeprovider.hxx>

#include <com/sun/star/beans/MethodConcept.hpp>
#include <com/sun/star/reflection/ParamMode.hpp>

using com::sun::star::beans::UnknownPropertyException;
using com::sun::star::beans::XIntrospectionAccess;

using namespace com::sun::star::lang;
using namespace com::sun::star::reflection;
using namespace com::sun::star::script;
using namespace com::sun::star::uno;

using namespace rtl;

#define OUSTRTOASCII(s) OUStringToOString(s, RTL_TEXTENCODING_ASCII_US).getStr()

#define LUNO_ADAPTER_PUSH_WRAPPED(ref) \
    LUNO_PUSH_REG_WRAPPED(); \
    lua_rawgeti(L, -1, ref); \
    lua_replace(L, -2)

#define LUNO_ADAPTER_PUSH_ADAPTERS(ref) \
    LUNO_PUSH_REG_ADAPTERS(); \
    lua_rawgeti(L, -1, ref); \
    lua_replace(L, -2)

namespace luno
{

/** Wraps table at index.
*/
LunoAdapter::LunoAdapter(lua_State *L_, const int index,
                        const Any &aTypes, const Any &aImpleId)
    : L(L_),
      m_WrappedRef(0),
      m_AdapterRef(0),
      m_Types(aTypes),
      m_ImpleId(aImpleId)
{
    const int top = lua_gettop(L);
    // push wrapped value to wrapped
    LUNO_PUSH_REG_WRAPPED();
    lua_pushvalue(L, index);
    m_WrappedRef = luaL_ref(L, -2);

    LUNO_PUSH_REG_ADAPTERS();
    lua_pushlightuserdata(L, this);
    m_AdapterRef = luaL_ref(L, -2);

    lua_settop(L, top);
}

LunoAdapter::~LunoAdapter()
{
    const int top = lua_gettop(L);
    if (m_WrappedRef)
    {
        LUNO_PUSH_REG_WRAPPED();
        luaL_unref(L, -1, m_WrappedRef);
        m_WrappedRef = 0;
    }
    if (m_AdapterRef)
    {
        LUNO_PUSH_REG_ADAPTERS();
        luaL_unref(L, -1, m_AdapterRef);
        m_AdapterRef = 0;
    }
    lua_settop(L, top);
}

LunoAdapter *LunoAdapter::create(lua_State *L_, const int index,
                            const Sequence< Type > &aTypes, const Sequence< sal_Int8 > &aImpleId)
{
    // ToDo get types and id at first request
    Any aTypes_;
    Any aImpleId_;
    aTypes_ <<= aTypes;
    aImpleId_ <<= aImpleId;

    return new LunoAdapter(L_, index, aTypes_, aImpleId_);
}

Sequence< sal_Int16 > LunoAdapter::getOutParamIndexes(const OUString &aName)
        throw (RuntimeException)
{
    Sequence< sal_Int16 > ret;

    Runtime runtime;
    Reference< XInterface > rAdapter(
        runtime.getImple()->xAdapterFactory->createAdapter(this, getWrappedTypes()));
    Reference< XIntrospectionAccess > xIntrospectionAcc(
        runtime.getImple()->xIntrospection->inspect(makeAny(rAdapter)));
    if (!xIntrospectionAcc.is())
        throw RuntimeException(
            OUSTRCONST("Failed to create adapter."), Reference< XInterface >());

    Reference< XIdlMethod > xIdlMethod(
        xIntrospectionAcc->getMethod(aName, com::sun::star::beans::MethodConcept::ALL));
    if (!xIdlMethod.is())
        throw RuntimeException(
            OUSTRCONST("Failed to get reflection for ") + aName, Reference< XInterface >());

    const Sequence< ParamInfo > aInfos(xIdlMethod->getParameterInfos());
    const ParamInfo *pInfos = aInfos.getConstArray();

    const int length = aInfos.getLength();
    int out = 0;
    int i = 0;
    for (i = 0; i < length; ++i)
    {
        if (pInfos[i].aMode != ParamMode_IN)
            ++out;
    }
    if (out)
    {
        sal_Int16 j = 0;
        ret.realloc(out);
        sal_Int16 *pOutIndexes = ret.getArray();
        for (i = 0; i < length; ++i)
        {
            if (pInfos[i].aMode != ParamMode_IN)
            {
                pOutIndexes[j] = i;
                ++j;
            }
        }
    }
    return ret;
}

Reference< XIntrospectionAccess > LunoAdapter::getIntrospection()
    throw (RuntimeException)
{
    return Reference< XIntrospectionAccess >();
}

Sequence< Type > LunoAdapter::getWrappedTypes() const
{
    Sequence< Type > aTypes;
    m_Types >>= aTypes;
    return aTypes;
}

// Call lua_gettable in safe mode
static int luno_gettable(lua_State *L)
{
    // 1: table, 2: key
    lua_pushvalue(L, 2); // key
    lua_gettable(L, 1);
    return 1;
}

#define THROW_ON_ERROR(error) \
    if (error) \
    { \
        size_t length; \
        const char *message = lua_tolstring(L, -1, &length); \
        const OUString aMessage(message, length, RTL_TEXTENCODING_UTF8); \
        lua_pop(L, 1); \
        throw RuntimeException(aMessage, Reference< XInterface >()); \
    }

#define CHECK_WRAPPED(ref) \
    if (!ref) \
        throw RuntimeException(OUSTRCONST("Nothing wrapped"), Reference< XInterface >())

Any LunoAdapter::invoke(const OUString &aName, const Sequence< Any > &aParams,
                    Sequence< sal_Int16 > &aOutParamIndex, Sequence< Any > &aOutParam)
    throw (IllegalArgumentException, CannotConvertException,
            InvocationTargetException,  RuntimeException)
{
    static const OUString aNameGetSomething(RTL_CONSTASCII_USTRINGPARAM("getSomething"));
    static const OUString aNameGetTypes(RTL_CONSTASCII_USTRINGPARAM("getTypes"));
    static const OUString aNameGetImplementationId(RTL_CONSTASCII_USTRINGPARAM("getImplementationId"));

    const int nParams = (int)aParams.getLength();
    if (!nParams)
    {
        // return cached value
        if (aName.equals(aNameGetTypes))
            return m_Types;
        else if (aName.equals(aNameGetImplementationId))
            return m_ImpleId;
    }
    else if (nParams == 1 && aName.equals(aNameGetSomething))
    {
        Sequence< sal_Int8 > id;
        if (aParams[0] >>= id)
            return makeAny(getSomething(id));
    }

    Any retAny;
    const int top = lua_gettop(L);
    try
    {
        CHECK_WRAPPED(m_WrappedRef);

        Runtime runtime;

        LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef); // reuse
        // find function to call with error checking
        lua_pushcfunction(L, luno_gettable);
        lua_pushvalue(L, -2); // wrapped
        lua_pushstring(L, OUSTRTOASCII(aName));
        const int e = lua_pcall(L, 2, 1, 0);
        THROW_ON_ERROR(e);

        if (!lua_isfunction(L, -1))
        {
            // ToDo check is callable?
            lua_settop(L, top);
            throw RuntimeException(
                OUSTRCONST("Method not found: ") + aName, Reference< XInterface >());
        }
        lua_insert(L, top + 1); // wrapped - func -> func - wrapped

        // push arguments
        const Any *pParams = aParams.getConstArray();
        for (int i = 0; i < nParams; ++i)
            runtime.anyToLua(L, pParams[i]);

        // call, obj + params, var args
        const int error = lua_pcall(L, nParams + 1, LUA_MULTRET, 0);
        if (error)
        {
            // ToDo test throw exception from Lua
            if (error == LUA_ERRRUN)
            {
                if (lua_isuserdata(L, -1))
                {
                    LunoAdapted *p = luno_proxy_getudata(L, -1, LUNO_META_STRUCT);
                    if (p != NULL && p->Wrapped.getValueTypeClass() == TypeClass_EXCEPTION)
                    {
                        lua_settop(L, top);
                        Exception e;
                        p->Wrapped >>= e;
                        throw InvocationTargetException(e.Message,
                                    Reference< XInterface >(), p->Wrapped);
                    }
                }
                size_t length;
                const char *message = lua_tolstring(L, -1, &length);
                throw RuntimeException(OUString(message, length, RTL_TEXTENCODING_UTF8),
                            Reference< XInterface >());
            }
            else
            {
                // ToDo LUA_ERRGCMM
                size_t length;
                const char *s = lua_tolstring(L, -1, &length);
                throw RuntimeException(
                    OUString(s, length, RTL_TEXTENCODING_UTF8), Reference< XInterface >());
            }
        }
        // ignore normal return value and wrapped obj
        const int nOut = lua_gettop(L) - top - 1;

        if (lua_gettop(L) - top > 0)
            retAny = runtime.luaToAny(L, top + 1);

        if (nOut > 1)
        {
            aOutParamIndex = getOutParamIndexes(aName);
            const int nOutParams = (int)aOutParamIndex.getLength();
            if (nOut != nOutParams)
                throw RuntimeException(
                    OUSTRCONST("luno: illegal number of out values for method: ") + aName,
                    Reference< XInterface >());

            aOutParam.realloc(nOutParams);
            for (int i = 0; i < nOutParams; ++i)
                aOutParam[i] = runtime.luaToAny(L, top + 1 + i);
        }
        lua_settop(L, top);
    }
    catch (RuntimeException &e)
    {
        lua_settop(L, top);
        throw;
    }
    return retAny;
}

// Call lua_settable in safe mode
static int luno_settable(lua_State *L)
{
    // i: table, 2: key, 3: value
    lua_pushvalue(L, 2); // key
    lua_pushvalue(L, 3); // value
    lua_settable(L, 1);
    return 0;
}

void LunoAdapter::setValue(const OUString &aName, const Any &aValue)
    throw (UnknownPropertyException, CannotConvertException,
            InvocationTargetException, RuntimeException)
{
    CHECK_WRAPPED(m_WrappedRef);

    lua_pushcfunction(L, luno_settable);
    LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef);
    lua_pushstring(L, OUSTRTOASCII(aName));

    try
    {
        Runtime runtime;
        runtime.anyToLua(L, aValue);
    }
    catch (RuntimeException &e)
    {
        lua_pop(L, 3);
        throw;
    }

    const int e = lua_pcall(L, 3, 1, 0);
    THROW_ON_ERROR(e);
}

Any LunoAdapter::getValue(const OUString &aName)
    throw (UnknownPropertyException, RuntimeException)
{
    CHECK_WRAPPED(m_WrappedRef);

    const int top = lua_gettop(L);
    Any a;

    lua_pushcfunction(L, luno_gettable);
    LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef);
    lua_pushstring(L, OUSTRTOASCII(aName));

    const int e = lua_pcall(L, 2, 1, 0);
    THROW_ON_ERROR(e);

    Runtime runtime;
    try
    {
        a = runtime.luaToAny(L, -1);
    }
    catch (RuntimeException &e)
    {
        lua_settop(L, top);
        throw;
    }
    lua_pop(L, 1); // result
    return a;
}

sal_Bool LunoAdapter::hasMethod(const OUString &aName)
    throw (RuntimeException)
{
    sal_Bool b = sal_False;
    CHECK_WRAPPED(m_WrappedRef);

    lua_pushcfunction(L, luno_gettable);
    LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef);
    lua_pushstring(L, OUSTRTOASCII(aName));

    const int e = lua_pcall(L, 2, 1, 0);
    THROW_ON_ERROR(e);

    if (!lua_isfunction(L, -1))
        b = sal_True;
    lua_pop(L, 1); // value
    return b;
}

sal_Bool LunoAdapter::hasProperty(const OUString &aName)
    throw (RuntimeException)
{
    CHECK_WRAPPED(m_WrappedRef);

    sal_Bool b = sal_False;
    lua_pushcfunction(L, luno_gettable);
    LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef);
    lua_pushstring(L, OUSTRTOASCII(aName));

    const int e = lua_pcall(L, 2, 1, 0);
    THROW_ON_ERROR(e);

    if (!lua_isnil(L, -1))
        b = sal_True;
    lua_pop(L, 1); // value
    return b;
}

static cppu::OImplementationId g_Id(sal_False);

Sequence< sal_Int8 > LunoAdapter::getUnoTunnelImplementationId()
{
    return g_Id.getImplementationId();
}

sal_Int64 LunoAdapter::getSomething(const Sequence< sal_Int8 > &aIdentifier)
    throw (RuntimeException)
{
    if (aIdentifier == g_Id.getImplementationId())
        return reinterpret_cast< sal_Int64 >(this);
    return 0;
}

} // luno
<commit_msg>Fix to extract struct from XMaterialHolder<commit_after>/*
** See Copyright Notice in LICENSE.
**/
#include "luno.hxx"

#include <cppuhelper/typeprovider.hxx>

#include <com/sun/star/beans/MethodConcept.hpp>
#include <com/sun/star/beans/XMaterialHolder.hpp>
#include <com/sun/star/reflection/ParamMode.hpp>

using com::sun::star::beans::UnknownPropertyException;
using com::sun::star::beans::XIntrospectionAccess;

using namespace com::sun::star::beans;
using namespace com::sun::star::lang;
using namespace com::sun::star::reflection;
using namespace com::sun::star::script;
using namespace com::sun::star::uno;

using namespace rtl;

#define OUSTRTOASCII(s) OUStringToOString(s, RTL_TEXTENCODING_ASCII_US).getStr()

#define LUNO_ADAPTER_PUSH_WRAPPED(ref) \
    LUNO_PUSH_REG_WRAPPED(); \
    lua_rawgeti(L, -1, ref); \
    lua_replace(L, -2)

#define LUNO_ADAPTER_PUSH_ADAPTERS(ref) \
    LUNO_PUSH_REG_ADAPTERS(); \
    lua_rawgeti(L, -1, ref); \
    lua_replace(L, -2)

namespace luno
{

/** Wraps table at index.
*/
LunoAdapter::LunoAdapter(lua_State *L_, const int index,
                        const Any &aTypes, const Any &aImpleId)
    : L(L_),
      m_WrappedRef(0),
      m_AdapterRef(0),
      m_Types(aTypes),
      m_ImpleId(aImpleId)
{
    const int top = lua_gettop(L);
    // push wrapped value to wrapped
    LUNO_PUSH_REG_WRAPPED();
    lua_pushvalue(L, index);
    m_WrappedRef = luaL_ref(L, -2);

    LUNO_PUSH_REG_ADAPTERS();
    lua_pushlightuserdata(L, this);
    m_AdapterRef = luaL_ref(L, -2);

    lua_settop(L, top);
}

LunoAdapter::~LunoAdapter()
{
    const int top = lua_gettop(L);
    if (m_WrappedRef)
    {
        LUNO_PUSH_REG_WRAPPED();
        luaL_unref(L, -1, m_WrappedRef);
        m_WrappedRef = 0;
    }
    if (m_AdapterRef)
    {
        LUNO_PUSH_REG_ADAPTERS();
        luaL_unref(L, -1, m_AdapterRef);
        m_AdapterRef = 0;
    }
    lua_settop(L, top);
}

LunoAdapter *LunoAdapter::create(lua_State *L_, const int index,
                            const Sequence< Type > &aTypes, const Sequence< sal_Int8 > &aImpleId)
{
    // ToDo get types and id at first request
    Any aTypes_;
    Any aImpleId_;
    aTypes_ <<= aTypes;
    aImpleId_ <<= aImpleId;

    return new LunoAdapter(L_, index, aTypes_, aImpleId_);
}

Sequence< sal_Int16 > LunoAdapter::getOutParamIndexes(const OUString &aName)
        throw (RuntimeException)
{
    Sequence< sal_Int16 > ret;

    Runtime runtime;
    Reference< XInterface > rAdapter(
        runtime.getImple()->xAdapterFactory->createAdapter(this, getWrappedTypes()));
    Reference< XIntrospectionAccess > xIntrospectionAcc(
        runtime.getImple()->xIntrospection->inspect(makeAny(rAdapter)));
    if (!xIntrospectionAcc.is())
        throw RuntimeException(
            OUSTRCONST("Failed to create adapter."), Reference< XInterface >());

    Reference< XIdlMethod > xIdlMethod(
        xIntrospectionAcc->getMethod(aName, com::sun::star::beans::MethodConcept::ALL));
    if (!xIdlMethod.is())
        throw RuntimeException(
            OUSTRCONST("Failed to get reflection for ") + aName, Reference< XInterface >());

    const Sequence< ParamInfo > aInfos(xIdlMethod->getParameterInfos());
    const ParamInfo *pInfos = aInfos.getConstArray();

    const int length = aInfos.getLength();
    int out = 0;
    int i = 0;
    for (i = 0; i < length; ++i)
    {
        if (pInfos[i].aMode != ParamMode_IN)
            ++out;
    }
    if (out)
    {
        sal_Int16 j = 0;
        ret.realloc(out);
        sal_Int16 *pOutIndexes = ret.getArray();
        for (i = 0; i < length; ++i)
        {
            if (pInfos[i].aMode != ParamMode_IN)
            {
                pOutIndexes[j] = i;
                ++j;
            }
        }
    }
    return ret;
}

Reference< XIntrospectionAccess > LunoAdapter::getIntrospection()
    throw (RuntimeException)
{
    return Reference< XIntrospectionAccess >();
}

Sequence< Type > LunoAdapter::getWrappedTypes() const
{
    Sequence< Type > aTypes;
    m_Types >>= aTypes;
    return aTypes;
}

// Call lua_gettable in safe mode
static int luno_gettable(lua_State *L)
{
    // 1: table, 2: key
    lua_pushvalue(L, 2); // key
    lua_gettable(L, 1);
    return 1;
}

#define THROW_ON_ERROR(error) \
    if (error) \
    { \
        size_t length; \
        const char *message = lua_tolstring(L, -1, &length); \
        const OUString aMessage(message, length, RTL_TEXTENCODING_UTF8); \
        lua_pop(L, 1); \
        throw RuntimeException(aMessage, Reference< XInterface >()); \
    }

#define CHECK_WRAPPED(ref) \
    if (!ref) \
        throw RuntimeException(OUSTRCONST("Nothing wrapped"), Reference< XInterface >())

Any LunoAdapter::invoke(const OUString &aName, const Sequence< Any > &aParams,
                    Sequence< sal_Int16 > &aOutParamIndex, Sequence< Any > &aOutParam)
    throw (IllegalArgumentException, CannotConvertException,
            InvocationTargetException,  RuntimeException)
{
    static const OUString aNameGetSomething(RTL_CONSTASCII_USTRINGPARAM("getSomething"));
    static const OUString aNameGetTypes(RTL_CONSTASCII_USTRINGPARAM("getTypes"));
    static const OUString aNameGetImplementationId(RTL_CONSTASCII_USTRINGPARAM("getImplementationId"));

    const int nParams = (int)aParams.getLength();
    if (!nParams)
    {
        // return cached value
        if (aName.equals(aNameGetTypes))
            return m_Types;
        else if (aName.equals(aNameGetImplementationId))
            return m_ImpleId;
    }
    else if (nParams == 1 && aName.equals(aNameGetSomething))
    {
        Sequence< sal_Int8 > id;
        if (aParams[0] >>= id)
            return makeAny(getSomething(id));
    }

    Any retAny;
    const int top = lua_gettop(L);
    try
    {
        CHECK_WRAPPED(m_WrappedRef);

        Runtime runtime;

        LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef); // reuse
        // find function to call with error checking
        lua_pushcfunction(L, luno_gettable);
        lua_pushvalue(L, -2); // wrapped
        lua_pushstring(L, OUSTRTOASCII(aName));
        const int e = lua_pcall(L, 2, 1, 0);
        THROW_ON_ERROR(e);

        if (!lua_isfunction(L, -1))
        {
            // ToDo check is callable?
            lua_settop(L, top);
            throw RuntimeException(
                OUSTRCONST("Method not found: ") + aName, Reference< XInterface >());
        }
        lua_insert(L, top + 1); // wrapped - func -> func - wrapped

        // push arguments
        const Any *pParams = aParams.getConstArray();
        for (int i = 0; i < nParams; ++i)
            runtime.anyToLua(L, pParams[i]);

        // call, obj + params, var args
        const int error = lua_pcall(L, nParams + 1, LUA_MULTRET, 0);
        if (error)
        {
            // ToDo test throw exception from Lua
            if (error == LUA_ERRRUN)
            {
                if (lua_isuserdata(L, -1))
                {
                    LunoAdapted *p = luno_proxy_getudata(L, -1, LUNO_META_STRUCT);
                    if (p != NULL && p->Wrapped.getValueTypeClass() == TypeClass_EXCEPTION)
                    {
                        Reference< XMaterialHolder > xMaterialHolder(
                                            p->xInvocation, UNO_QUERY);
                        if (xMaterialHolder.is())
                        {
                            Exception e;
                            xMaterialHolder->getMaterial() >>= e;
                            lua_settop(L, top);
                            throw InvocationTargetException(e.Message,
                                        Reference< XInterface >(), xMaterialHolder->getMaterial());
                        }
                    }
                }
                size_t length;
                const char *message = lua_tolstring(L, -1, &length);
                lua_settop(L, top);
                throw RuntimeException(OUString(message, length, RTL_TEXTENCODING_UTF8),
                            Reference< XInterface >());
            }
            else
            {
                // ToDo LUA_ERRGCMM
                size_t length;
                const char *s = lua_tolstring(L, -1, &length);
                throw RuntimeException(
                    OUString(s, length, RTL_TEXTENCODING_UTF8), Reference< XInterface >());
            }
        }
        // ignore normal return value and wrapped obj
        const int nOut = lua_gettop(L) - top - 1;

        if (lua_gettop(L) - top > 0)
            retAny = runtime.luaToAny(L, top + 1);

        if (nOut > 1)
        {
            aOutParamIndex = getOutParamIndexes(aName);
            const int nOutParams = (int)aOutParamIndex.getLength();
            if (nOut != nOutParams)
                throw RuntimeException(
                    OUSTRCONST("luno: illegal number of out values for method: ") + aName,
                    Reference< XInterface >());

            aOutParam.realloc(nOutParams);
            for (int i = 0; i < nOutParams; ++i)
                aOutParam[i] = runtime.luaToAny(L, top + 1 + i);
        }
        lua_settop(L, top);
    }
    catch (RuntimeException &e)
    {
        lua_settop(L, top);
        throw;
    }
    return retAny;
}

// Call lua_settable in safe mode
static int luno_settable(lua_State *L)
{
    // i: table, 2: key, 3: value
    lua_pushvalue(L, 2); // key
    lua_pushvalue(L, 3); // value
    lua_settable(L, 1);
    return 0;
}

void LunoAdapter::setValue(const OUString &aName, const Any &aValue)
    throw (UnknownPropertyException, CannotConvertException,
            InvocationTargetException, RuntimeException)
{
    CHECK_WRAPPED(m_WrappedRef);

    lua_pushcfunction(L, luno_settable);
    LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef);
    lua_pushstring(L, OUSTRTOASCII(aName));

    try
    {
        Runtime runtime;
        runtime.anyToLua(L, aValue);
    }
    catch (RuntimeException &e)
    {
        lua_pop(L, 3);
        throw;
    }

    const int e = lua_pcall(L, 3, 1, 0);
    THROW_ON_ERROR(e);
}

Any LunoAdapter::getValue(const OUString &aName)
    throw (UnknownPropertyException, RuntimeException)
{
    CHECK_WRAPPED(m_WrappedRef);

    const int top = lua_gettop(L);
    Any a;

    lua_pushcfunction(L, luno_gettable);
    LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef);
    lua_pushstring(L, OUSTRTOASCII(aName));

    const int e = lua_pcall(L, 2, 1, 0);
    THROW_ON_ERROR(e);

    Runtime runtime;
    try
    {
        a = runtime.luaToAny(L, -1);
    }
    catch (RuntimeException &e)
    {
        lua_settop(L, top);
        throw;
    }
    lua_pop(L, 1); // result
    return a;
}

sal_Bool LunoAdapter::hasMethod(const OUString &aName)
    throw (RuntimeException)
{
    sal_Bool b = sal_False;
    CHECK_WRAPPED(m_WrappedRef);

    lua_pushcfunction(L, luno_gettable);
    LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef);
    lua_pushstring(L, OUSTRTOASCII(aName));

    const int e = lua_pcall(L, 2, 1, 0);
    THROW_ON_ERROR(e);

    if (!lua_isfunction(L, -1))
        b = sal_True;
    lua_pop(L, 1); // value
    return b;
}

sal_Bool LunoAdapter::hasProperty(const OUString &aName)
    throw (RuntimeException)
{
    CHECK_WRAPPED(m_WrappedRef);

    sal_Bool b = sal_False;
    lua_pushcfunction(L, luno_gettable);
    LUNO_ADAPTER_PUSH_WRAPPED(m_WrappedRef);
    lua_pushstring(L, OUSTRTOASCII(aName));

    const int e = lua_pcall(L, 2, 1, 0);
    THROW_ON_ERROR(e);

    if (!lua_isnil(L, -1))
        b = sal_True;
    lua_pop(L, 1); // value
    return b;
}

static cppu::OImplementationId g_Id(sal_False);

Sequence< sal_Int8 > LunoAdapter::getUnoTunnelImplementationId()
{
    return g_Id.getImplementationId();
}

sal_Int64 LunoAdapter::getSomething(const Sequence< sal_Int8 > &aIdentifier)
    throw (RuntimeException)
{
    if (aIdentifier == g_Id.getImplementationId())
        return reinterpret_cast< sal_Int64 >(this);
    return 0;
}

} // luno
<|endoftext|>


<commit_before>/**
 * @author pinkasfeld joseph
 * Copyright (c) Aldebaran Robotics 2010, 2011 All Rights Reserved.
 */

#include "allaser.h"

#include <iostream>
#include <alcommon/alproxy.h>
#include <alproxies/almemoryproxy.h>
#include <boost/shared_ptr.hpp>
#include <alcommon/albroker.h>
#include <alcommon/almodule.h>

#include <pthread.h>
#include <signal.h>
#include <math.h>
#include <rttools/rtprintf.h>

#if defined (__linux__)
#include <sys/prctl.h>
#endif

extern "C" {
# include "urg_ctrl.h"
# include "scip_handler.h"
}

#define MODE_ON 0
#define MODE_OFF 1
#define SEND_MODE_ON 2
#define SEND_MODE_OFF 3

#define MIDDLE_ANGLE 384
#define DEFAULT_MIN_ANGLE 43
#define DEFAULT_MAX_ANGLE 725
#define MIN_ANGLE_LASER 43
#define MAX_ANGLE_LASER 725
#define RESOLUTION_LASER 1024
#define MIN_LENGTH_LASER 20
#define MAX_LENGTH_LASER 5600

#include <sys/time.h>

using namespace AL;
using namespace std;
pthread_t urgThreadId;
boost::shared_ptr<ALMemoryProxy> gSTM;
static int mode = MODE_ON;
static urg_t urg;
static int angle_min = DEFAULT_MIN_ANGLE;
static int angle_max = DEFAULT_MAX_ANGLE;
static int length_min = MIN_LENGTH_LASER;
static int length_max = MAX_LENGTH_LASER;

static void urg_exit(urg_t *urg, const char *message) {
  rtprintf("%s: %s\n", message, urg_error(urg));
  urg_disconnect(urg);
  rtprintf("ALLaser : urg_exit\n");
  pthread_exit((void *)NULL);
}

#define URG_DEFAULT_SPEED (19200)
#define URG_FAST_SPEED (500000)

void * urgThread(void * arg) {

#if defined (__linux__)
  // thread name
  prctl(PR_SET_NAME, "ALLaser::urgThread", 0, 0, 0);
#endif

  ALValue urgdata;
  long *data = NULL;
  int data_max;
  int ret;
  int n;
  int i,imemory,refTime,end,sampleTime, beginThread;
  std::string valueName="Device/Laser/Value";

  /* Connection */

  connectToLaser();

  /* Reserve the Receive data buffer */
  data_max = urg_dataMax(&urg);
  data = (long*)malloc(sizeof(long) * data_max);
  if (data == NULL) {
    perror("data buffer");
    pthread_exit((void *)NULL);
  }
  /* prepare ALValue for ALMemory*/
  urgdata.arraySetSize(data_max);
  for (i=0; i< data_max;i++)
  {
    urgdata[i].arraySetSize(4);
    urgdata[i][0]= (int)0;
    urgdata[i][1]= (double)0.0;
    urgdata[i][2]= (int)0;
    urgdata[i][3]= (int)0;
    //urgdata[i][4]= (int)0;
  }
  /* insert ALvalue in ALMemory*/

  gSTM->insertData(valueName,urgdata);

  gSTM->insertData("Device/Laser/LaserEnable",(bool)1);
  gSTM->insertData("Device/Laser/MinAngle",(float)((2.0 * M_PI)*(DEFAULT_MIN_ANGLE - MIDDLE_ANGLE) / RESOLUTION_LASER));
  gSTM->insertData("Device/Laser/MaxAngle",(float)((2.0 * M_PI)*(DEFAULT_MAX_ANGLE - MIDDLE_ANGLE) / RESOLUTION_LASER));
  gSTM->insertData("Device/Laser/MinLength",(float)(length_min));
  gSTM->insertData("Device/Laser/MaxLength",(float)(length_max));

  printf("ALLASER Running\n");

  while(1)
  {
    if(mode==SEND_MODE_ON){
      ret = urg_laserOn(&urg);
      if (ret < 0) {
        urg_exit(&urg, "urg_requestData()");
      }
      mode=MODE_ON;
      /* Connection */
      connectToLaser();
    }
    if(mode==SEND_MODE_OFF){
      scip_qt(&urg.serial_, NULL, ScipNoWaitReply);
      mode=MODE_OFF;
    }
    if(mode==MODE_ON){
      /* Request Data using GD-Command */
      ret = urg_requestData(&urg, URG_GD, angle_min, angle_max);
      if (ret < 0) {
        urg_exit(&urg, "urg_requestData()");
      }

      refTime = getLocalTime();
      /* Obtain Data */
      n = urg_receiveData(&urg, data, data_max);
      if (n < 0) {
        urg_exit(&urg, "urg_receiveData()");
      }
      end= getLocalTime();
      sampleTime=end-refTime;

      imemory=0;
      for (i = 0; i < n; ++i) {
        int x, y;
        double angle=index2rad(i);
        int length = data[i];

        if((length>=length_min)&&(length<=length_max)){
          x = (int)((double)length * cos(angle));
          y = (int)((double)length * sin(angle));
          urgdata[imemory][0]= length;
          urgdata[imemory][1]= angle;
          urgdata[imemory][2]= x;
          urgdata[imemory][3]= y;
          //urgdata[imemory][4]= refTime+i*sampleTime/data_max;
          imemory++;
        }
      }
      for(;imemory<data_max;imemory++){
        urgdata[imemory][0]= 0;
        urgdata[imemory][1]= 0;
        urgdata[imemory][2]= 0;
        urgdata[imemory][3]= 0;
        //urgdata[imemory][4]= 0;
      }
      gSTM->insertData(valueName,urgdata);
      usleep(1000);
    }else{
      usleep(10000);
    }
  }
  urg_disconnect(&urg);

  free(data);
}

//______________________________________________
// constructor
//______________________________________________
ALLaser::ALLaser(boost::shared_ptr<ALBroker> pBroker, const std::string& pName ): ALModule(pBroker, pName )
{
  setModuleDescription( "Allow control over Hokuyo laser when available on Nao's head." );

  functionName("laserOFF", "ALLaser", "Disable laser light");
  BIND_METHOD( ALLaser::laserOFF );

  functionName("laserON", "ALLaser", "Enable laser light and sampling");
  BIND_METHOD( ALLaser::laserON );

  functionName("setOpeningAngle", "ALLaser", "Set openning angle of the laser");
  addParam("angle_min_f", "float containing the min value in rad, this value must be upper than -2.35619449 ");
  addParam("angle_max_f", "float containing the max value in rad, this value must be lower than 2.092349795 ");
  addMethodExample( "python",
        "# Set the opening angle at -90/90 degres\n"
        "laser = ALProxy(\"ALLaser\",\"127.0.0.1\",9559)\n"
        "laser.setOpeningAngle(-1.570796327,1.570796327)\n"
      );
  BIND_METHOD( ALLaser::setOpeningAngle );

  functionName("setDetectingLength", "ALLaser", "Set detection threshold of the laser");
  addParam("length_min_l", "int containing the min length that the laser will detect(mm), this value must be upper than 20 mm");
  addParam("length_max_l", "int containing the max length that the laser will detect(mm), this value must be lower than 5600 mm");
  addMethodExample( "python",
        "# Set detection threshold at 500/3000 mm\n"
        "laser = ALProxy(\"ALLaser\",\"127.0.0.1\",9559)\n"
        "laser.setDetectingLength(500,3000)\n"
      );
  BIND_METHOD( ALLaser::setDetectingLength );

  // get broker on DCM and ALMemory
  try {
    gSTM = getParentBroker()->getMemoryProxy();
  } catch(ALError& e) {
    std::cout << "LASER could not connect to Memory. Error : " << e.toString() << endl;
  }

  pthread_create(&urgThreadId, NULL, urgThread, NULL);
}

//______________________________________________
// destructor
//______________________________________________
ALLaser::~ALLaser()
{
  pthread_cancel(urgThreadId);
}

void ALLaser::laserOFF(void){
  mode = SEND_MODE_OFF;
  gSTM->insertData("Device/Laser/LaserEnable",(bool)0);
}

void ALLaser::laserON(void){
  mode = SEND_MODE_ON;
  gSTM->insertData("Device/Laser/LaserEnable",(bool)1);
}

void ALLaser::setOpeningAngle(const AL::ALValue& angle_min_f, const AL::ALValue& angle_max_f){
  angle_min = MIDDLE_ANGLE + (int)(RESOLUTION_LASER*(float)angle_min_f / (2.0 * M_PI));
  angle_max = MIDDLE_ANGLE + (int)(RESOLUTION_LASER*(float)angle_max_f / (2.0 * M_PI));
  if(angle_min<MIN_ANGLE_LASER) angle_min = MIN_ANGLE_LASER;
  if(angle_max>MAX_ANGLE_LASER) angle_max = MAX_ANGLE_LASER;
  if(angle_min>=angle_max){
    angle_min = MIN_ANGLE_LASER;
    angle_max = MAX_ANGLE_LASER;
  }
  gSTM->insertData("Device/Laser/MinAngle",(float)((2.0 * M_PI) *(angle_min - MIDDLE_ANGLE) / RESOLUTION_LASER));
  gSTM->insertData("Device/Laser/MaxAngle",(float)((2.0 * M_PI) *(angle_max - MIDDLE_ANGLE) / RESOLUTION_LASER));
}

void ALLaser::setDetectingLength(const AL::ALValue& length_min_l,const AL::ALValue& length_max_l){
  length_min=(int)length_min_l;
  length_max=(int)length_max_l;
  if(length_min<MIN_LENGTH_LASER) length_min = MIN_LENGTH_LASER;
  if(length_max>MAX_LENGTH_LASER) length_min = MAX_LENGTH_LASER;
  if(length_min>=length_max){
    length_min = MIN_LENGTH_LASER;
    length_max = MAX_LENGTH_LASER;
  }
  gSTM->insertData("Device/Laser/MinLength",(int)length_min);
  gSTM->insertData("Device/Laser/MaxLength",(int)length_max);
}

//_________________________________________________
// Service functions
//_________________________________________________

void connectToLaser(void){
  //const char device[] = "COM3"; /* Example when using Windows  */
  const char deviceACM[] = "/dev/ttyACM0"; /* Example when using Linux  */
  const char deviceUSB[] = "/dev/ttyUSB0"; /* Example when using Linux  */
  int ret;

  ret = urg_connect(&urg, deviceUSB, URG_DEFAULT_SPEED);
  if (ret < 0)
  {
    rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceUSB,URG_DEFAULT_SPEED, urg_error(&urg));
    ret = urg_connect(&urg, deviceUSB, URG_FAST_SPEED);
    if (ret < 0)
    {
      rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceUSB,URG_FAST_SPEED, urg_error(&urg));
      ret = urg_connect(&urg, deviceACM, URG_DEFAULT_SPEED);
      if (ret < 0)
      {
        rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceACM,URG_DEFAULT_SPEED, urg_error(&urg));
        ret = urg_connect(&urg, deviceACM, URG_FAST_SPEED);
        if (ret < 0)
        {
          rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceACM,URG_FAST_SPEED, urg_error(&urg));
          pthread_exit((void *)NULL);
        }
      }
      else
      {
        scip_ss(&urg.serial_, URG_FAST_SPEED);
        urg_disconnect(&urg);
        ret = urg_connect(&urg, deviceACM, URG_FAST_SPEED);
        if (ret < 0)
        {
          rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceACM,URG_FAST_SPEED, urg_error(&urg));
          pthread_exit((void *)NULL);
        }
      }
    }
  }
  else
  {
    /*switch to full speed*/
    scip_ss(&urg.serial_, URG_FAST_SPEED);
    urg_disconnect(&urg);
    ret = urg_connect(&urg, deviceUSB, URG_FAST_SPEED);
    if (ret < 0)
    {
      rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceUSB,URG_FAST_SPEED, urg_error(&urg));
      pthread_exit((void *)NULL);
    }
  }
}

unsigned int getLocalTime(void){
  struct timeval tv;
  unsigned int val;

  gettimeofday(&tv, NULL);

  val = (unsigned int)((unsigned int)(tv.tv_usec/1000) + (unsigned int)(tv.tv_sec*1000));
  //std::cout << val << std::endl;
  // Time in ms
  return val;
}

double index2rad(int index){

  double radian = (2.0 * M_PI) *
                  (index - MIDDLE_ANGLE + angle_min) / RESOLUTION_LASER;

  return radian;
}
<commit_msg>ALaser: Remove COUT ... most info as debug<commit_after>/**
 * @author pinkasfeld joseph
 * Copyright (c) Aldebaran Robotics 2010, 2011 All Rights Reserved.
 */

#include "allaser.h"

#include <iostream>
#include <alcommon/alproxy.h>
#include <alproxies/almemoryproxy.h>
#include <boost/shared_ptr.hpp>
#include <alcommon/albroker.h>
#include <alcommon/almodule.h>
#include <stringstream>

#include <pthread.h>
#include <signal.h>
#include <math.h>
#include <allog/allog.h>
#include <rttools/rtprintf.h>

#if defined (__linux__)
#include <sys/prctl.h>
#endif

extern "C" {
# include "urg_ctrl.h"
# include "scip_handler.h"
}

#define MODE_ON 0
#define MODE_OFF 1
#define SEND_MODE_ON 2
#define SEND_MODE_OFF 3

#define MIDDLE_ANGLE 384
#define DEFAULT_MIN_ANGLE 43
#define DEFAULT_MAX_ANGLE 725
#define MIN_ANGLE_LASER 43
#define MAX_ANGLE_LASER 725
#define RESOLUTION_LASER 1024
#define MIN_LENGTH_LASER 20
#define MAX_LENGTH_LASER 5600

#include <sys/time.h>

using namespace AL;
using namespace std;
pthread_t urgThreadId;
boost::shared_ptr<ALMemoryProxy> gSTM;
static int mode = MODE_ON;
static urg_t urg;
static int angle_min = DEFAULT_MIN_ANGLE;
static int angle_max = DEFAULT_MAX_ANGLE;
static int length_min = MIN_LENGTH_LASER;
static int length_max = MAX_LENGTH_LASER;

static void urg_exit(urg_t *urg, const char *message) {
  rtprintf("%s: %s\n", message, urg_error(urg));
  urg_disconnect(urg);
  rtprintf("ALLaser : urg_exit\n");
  pthread_exit((void *)NULL);
}

#define URG_DEFAULT_SPEED (19200)
#define URG_FAST_SPEED (500000)

void * urgThread(void * arg) {

#if defined (__linux__)
  // thread name
  prctl(PR_SET_NAME, "ALLaser::urgThread", 0, 0, 0);
#endif

  ALValue urgdata;
  long *data = NULL;
  int data_max;
  int ret;
  int n;
  int i,imemory,refTime,end,sampleTime, beginThread;
  std::string valueName="Device/Laser/Value";

  /* Connection */

  connectToLaser();

  /* Reserve the Receive data buffer */
  data_max = urg_dataMax(&urg);
  data = (long*)malloc(sizeof(long) * data_max);
  if (data == NULL) {
    perror("data buffer");
    pthread_exit((void *)NULL);
  }
  /* prepare ALValue for ALMemory*/
  urgdata.arraySetSize(data_max);
  for (i=0; i< data_max;i++)
  {
    urgdata[i].arraySetSize(4);
    urgdata[i][0]= (int)0;
    urgdata[i][1]= (double)0.0;
    urgdata[i][2]= (int)0;
    urgdata[i][3]= (int)0;
    //urgdata[i][4]= (int)0;
  }
  /* insert ALvalue in ALMemory*/

  gSTM->insertData(valueName,urgdata);

  gSTM->insertData("Device/Laser/LaserEnable",(bool)1);
  gSTM->insertData("Device/Laser/MinAngle",(float)((2.0 * M_PI)*(DEFAULT_MIN_ANGLE - MIDDLE_ANGLE) / RESOLUTION_LASER));
  gSTM->insertData("Device/Laser/MaxAngle",(float)((2.0 * M_PI)*(DEFAULT_MAX_ANGLE - MIDDLE_ANGLE) / RESOLUTION_LASER));
  gSTM->insertData("Device/Laser/MinLength",(float)(length_min));
  gSTM->insertData("Device/Laser/MaxLength",(float)(length_max));

  printf("ALLASER Running\n");

  while(1)
  {
    if(mode==SEND_MODE_ON){
      ret = urg_laserOn(&urg);
      if (ret < 0) {
        urg_exit(&urg, "urg_requestData()");
      }
      mode=MODE_ON;
      /* Connection */
      connectToLaser();
    }
    if(mode==SEND_MODE_OFF){
      scip_qt(&urg.serial_, NULL, ScipNoWaitReply);
      mode=MODE_OFF;
    }
    if(mode==MODE_ON){
      /* Request Data using GD-Command */
      ret = urg_requestData(&urg, URG_GD, angle_min, angle_max);
      if (ret < 0) {
        urg_exit(&urg, "urg_requestData()");
      }

      refTime = getLocalTime();
      /* Obtain Data */
      n = urg_receiveData(&urg, data, data_max);
      if (n < 0) {
        urg_exit(&urg, "urg_receiveData()");
      }
      end= getLocalTime();
      sampleTime=end-refTime;

      imemory=0;
      for (i = 0; i < n; ++i) {
        int x, y;
        double angle=index2rad(i);
        int length = data[i];

        if((length>=length_min)&&(length<=length_max)){
          x = (int)((double)length * cos(angle));
          y = (int)((double)length * sin(angle));
          urgdata[imemory][0]= length;
          urgdata[imemory][1]= angle;
          urgdata[imemory][2]= x;
          urgdata[imemory][3]= y;
          //urgdata[imemory][4]= refTime+i*sampleTime/data_max;
          imemory++;
        }
      }
      for(;imemory<data_max;imemory++){
        urgdata[imemory][0]= 0;
        urgdata[imemory][1]= 0;
        urgdata[imemory][2]= 0;
        urgdata[imemory][3]= 0;
        //urgdata[imemory][4]= 0;
      }
      gSTM->insertData(valueName,urgdata);
      usleep(1000);
    }else{
      usleep(10000);
    }
  }
  urg_disconnect(&urg);

  free(data);
}

//______________________________________________
// constructor
//______________________________________________
ALLaser::ALLaser(boost::shared_ptr<ALBroker> pBroker, const std::string& pName ): ALModule(pBroker, pName )
{
  setModuleDescription( "Allow control over Hokuyo laser when available on Nao's head." );

  functionName("laserOFF", "ALLaser", "Disable laser light");
  BIND_METHOD( ALLaser::laserOFF );

  functionName("laserON", "ALLaser", "Enable laser light and sampling");
  BIND_METHOD( ALLaser::laserON );

  functionName("setOpeningAngle", "ALLaser", "Set openning angle of the laser");
  addParam("angle_min_f", "float containing the min value in rad, this value must be upper than -2.35619449 ");
  addParam("angle_max_f", "float containing the max value in rad, this value must be lower than 2.092349795 ");
  addMethodExample( "python",
        "# Set the opening angle at -90/90 degres\n"
        "laser = ALProxy(\"ALLaser\",\"127.0.0.1\",9559)\n"
        "laser.setOpeningAngle(-1.570796327,1.570796327)\n"
      );
  BIND_METHOD( ALLaser::setOpeningAngle );

  functionName("setDetectingLength", "ALLaser", "Set detection threshold of the laser");
  addParam("length_min_l", "int containing the min length that the laser will detect(mm), this value must be upper than 20 mm");
  addParam("length_max_l", "int containing the max length that the laser will detect(mm), this value must be lower than 5600 mm");
  addMethodExample( "python",
        "# Set detection threshold at 500/3000 mm\n"
        "laser = ALProxy(\"ALLaser\",\"127.0.0.1\",9559)\n"
        "laser.setDetectingLength(500,3000)\n"
      );
  BIND_METHOD( ALLaser::setDetectingLength );

  // get broker on DCM and ALMemory
  try {
    gSTM = getParentBroker()->getMemoryProxy();
  } catch(ALError& e) {
    alserror << "ALLASER: could not connect to Memory. Error: " << e.what() << std::endl;
  }

  pthread_create(&urgThreadId, NULL, urgThread, NULL);
}

//______________________________________________
// destructor
//______________________________________________
ALLaser::~ALLaser()
{
  pthread_cancel(urgThreadId);
}

void ALLaser::laserOFF(void){
  mode = SEND_MODE_OFF;
  gSTM->insertData("Device/Laser/LaserEnable",(bool)0);
}

void ALLaser::laserON(void){
  mode = SEND_MODE_ON;
  gSTM->insertData("Device/Laser/LaserEnable",(bool)1);
}

void ALLaser::setOpeningAngle(const AL::ALValue& angle_min_f, const AL::ALValue& angle_max_f){
  angle_min = MIDDLE_ANGLE + (int)(RESOLUTION_LASER*(float)angle_min_f / (2.0 * M_PI));
  angle_max = MIDDLE_ANGLE + (int)(RESOLUTION_LASER*(float)angle_max_f / (2.0 * M_PI));
  if(angle_min<MIN_ANGLE_LASER) angle_min = MIN_ANGLE_LASER;
  if(angle_max>MAX_ANGLE_LASER) angle_max = MAX_ANGLE_LASER;
  if(angle_min>=angle_max){
    angle_min = MIN_ANGLE_LASER;
    angle_max = MAX_ANGLE_LASER;
  }
  gSTM->insertData("Device/Laser/MinAngle",(float)((2.0 * M_PI) *(angle_min - MIDDLE_ANGLE) / RESOLUTION_LASER));
  gSTM->insertData("Device/Laser/MaxAngle",(float)((2.0 * M_PI) *(angle_max - MIDDLE_ANGLE) / RESOLUTION_LASER));
}

void ALLaser::setDetectingLength(const AL::ALValue& length_min_l,const AL::ALValue& length_max_l){
  length_min=(int)length_min_l;
  length_max=(int)length_max_l;
  if(length_min<MIN_LENGTH_LASER) length_min = MIN_LENGTH_LASER;
  if(length_max>MAX_LENGTH_LASER) length_min = MAX_LENGTH_LASER;
  if(length_min>=length_max){
    length_min = MIN_LENGTH_LASER;
    length_max = MAX_LENGTH_LASER;
  }
  gSTM->insertData("Device/Laser/MinLength",(int)length_min);
  gSTM->insertData("Device/Laser/MaxLength",(int)length_max);
}

//_________________________________________________
// Service functions
//_________________________________________________

void connectToLaser(void){
  //const char device[] = "COM3"; /* Example when using Windows  */
  const char deviceACM[] = "/dev/ttyACM0"; /* Example when using Linux  */
  const char deviceUSB[] = "/dev/ttyUSB0"; /* Example when using Linux  */
  int ret;

  ret = urg_connect(&urg, deviceUSB, URG_DEFAULT_SPEED);
  if (ret < 0)
  {
	std::stringstream ss;
	ss << "ALLaser: Connection failure to " << deviceUSB << " at " << URG_DEFAULT_SPEED << ". " << urg_error(&urg);
	asldebug << ss.str();

    //alsdebug << "ALLaser : Fail connecting to %s at %d: %s\n", deviceUSB, URG_DEFAULT_SPEED, urg_error(&urg));
    ret = urg_connect(&urg, deviceUSB, URG_FAST_SPEED);
    if (ret < 0)
    {
	  std::stringstream ss;
	  ss << "ALLaser: Connection failure to " << deviceUSB << " at " << URG_FAST_SPEED << ". " << urg_error(&urg);
	  asldebug << ss.str();

      //rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceUSB,URG_FAST_SPEED, urg_error(&urg));
      ret = urg_connect(&urg, deviceACM, URG_DEFAULT_SPEED);
      if (ret < 0)
      {
	    std::stringstream ss;
	    ss << "ALLaser: Connection failure to " << deviceACM << " at " << URG_DEFAULT_SPEED << ". " << urg_error(&urg);
	    asldebug << ss.str();

        //rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceACM,URG_DEFAULT_SPEED, urg_error(&urg));
        ret = urg_connect(&urg, deviceACM, URG_FAST_SPEED);
        if (ret < 0)
        {
		  std::stringstream ss;
	      ss << "ALLaser: Connection failure to " << deviceACM << " at " << URG_FAST_SPEED << ". " << urg_error(&urg);
	      asldebug << ss.str();

          //rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceACM,URG_FAST_SPEED, urg_error(&urg));
          pthread_exit((void *)NULL);
        }
      }
      else
      {
        scip_ss(&urg.serial_, URG_FAST_SPEED);
        urg_disconnect(&urg);
        ret = urg_connect(&urg, deviceACM, URG_FAST_SPEED);
        if (ret < 0)
        {
		  std::stringstream ss;
	      ss << "ALLaser: Disconnect failure from " << deviceACM << " at " << URG_FAST_SPEED << ". " << urg_error(&urg);
	      asldebug << ss.str();

          //rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceACM,URG_FAST_SPEED, urg_error(&urg));
          pthread_exit((void *)NULL);
        }
      }
    }
  }
  else
  {
    /*switch to full speed*/
    scip_ss(&urg.serial_, URG_FAST_SPEED);
    urg_disconnect(&urg);
    ret = urg_connect(&urg, deviceUSB, URG_FAST_SPEED);
    if (ret < 0)
    {
	  std::stringstream ss;
	  ss << "ALLaser: Disconnect failure from " << deviceUSB << " at " << URG_FAST_SPEED << ". " << urg_error(&urg);
	  asldebug << ss.str();

      //rtprintf("ALLaser : Fail connecting to %s at %d: %s\n",deviceUSB,URG_FAST_SPEED, urg_error(&urg));
      pthread_exit((void *)NULL);
    }
  }
}

unsigned int getLocalTime(void){
  struct timeval tv;
  unsigned int val;

  gettimeofday(&tv, NULL);

  val = (unsigned int)((unsigned int)(tv.tv_usec/1000) + (unsigned int)(tv.tv_sec*1000));
  //std::cout << val << std::endl;
  // Time in ms
  return val;
}

double index2rad(int index){

  double radian = (2.0 * M_PI) *
                  (index - MIDDLE_ANGLE + angle_min) / RESOLUTION_LASER;

  return radian;
}
<|endoftext|>


<commit_before>#include "basecpu.h"
#include "errors.h"
#include "utils.h"

BaseCPU::BaseCPU(const System &sys): sys(sys), running(false) {
}

void BaseCPU::stop() {
    running = false;
}

bool BaseCPU::startup() {
    bool started = false;
    if (!running) {
        running = true;
        started = true;
        reset();
        while(running) { tick(); }
    }
    return started;
}

bool BaseCPU::isRunning() {
    return running;
}

int BaseCPU::readMemory(SizeType offset, SizeType len, void *data) const {
    return sys.readMemory(offset, len, data);
}

int BaseCPU::writeMemory(SizeType offset, SizeType len, const void *data) const {
    return sys.writeMemory(offset, len, data);
}

int BaseCPU::readPort(PortType port, SizeType len, void *data) const {
    return sys.readPort(port, len, data);
}

int BaseCPU::writePort(PortType port, SizeType len, const void *data) const {
    return sys.writePort(port, len, data);
}

void Interruptable::signalInterrupt(Interrupt interrupt) {
    interruptQueue.push(interrupt);
}

SizeType Interruptable::interruptQueueLength() {
    return interruptQueue.size();
}

bool Interruptable::serviceNextInterrupt() {
    bool ret = false;
    if(!interruptQueue.empty()) {
        serviceInterrupt(interruptQueue.front());
        interruptQueue.pop();
        ret = true;
    }
    return ret;
}

GenericCPU::GenericCPU(const System &sys, const InstructionSet &set, Interrupt badInstruction, Interrupt badOperand) :
    BaseCPU(sys), set(set), badInstruction(badInstruction), badOperand(badOperand) {
}

void GenericCPU::tick() {
    if(!(interruptsEnabled() && serviceNextInterrupt())) {
        nextInstruction();
    }
}

bool GenericCPU::readBytes(ByteString &buffer, const void * const base, SizeType length) {
    buffer.reserve(length);
    return readMemory((SizeType)base, length, buffer.data()) == ERR_SUCCESS;
}

bool GenericCPU::readNextByte(ByteString &buffer, const void * const base) {
    bool ret = false;
    byte next;
    SizeType nextAddr = ((SizeType)base) + buffer.size();

    if(readMemory(nextAddr, 1, &next) != ERR_SUCCESS) {
        ret = false;
    } else {
        buffer.push_back(next);
        ret = true;
    }
    return ret;
}

int GenericCPU::readInstruction(const void * const instructionBase, const Instruction **out) {
    ByteString opcode;
    bool memoryRc;
    int decodeRc;

    do {
        memoryRc = readNextByte(opcode, instructionBase);
        if(memoryRc) {
            decodeRc = set.decode(opcode, out);
        }
    } while(
        memoryRc && (decodeRc == ERR_CONFLICT || decodeRc == ERR_INCOMPLETE)
    );

    if(!memoryRc) {
        return ERR_CONFLICT;
    }

    if(decodeRc != ERR_SUCCESS) {
        return ERR_BADRANGE;
    } else {
        return ERR_SUCCESS;
    }
}

bool GenericCPU::readInstructionOperands(
    const void * const instructionBase,
    const Instruction &instruction,
    ByteString &operands
) {
    const void * const operandBase = advancePtr(instructionBase, instruction.opcode.size());
    return readBytes(operands, operandBase, instruction.length);
}

bool GenericCPU::loadNextInstruction(const Instruction **instruction, ByteString &operands) {
    bool instructionLoaded = false;
    const void * const instructionBase = getInstructionPointer();
    int instructionRc = readInstruction(instructionBase, instruction);
    if(instructionRc == ERR_SUCCESS) {
        bool operandRc = readInstructionOperands(instructionBase, **instruction, operands);
        if(!operandRc) {
            signalInterrupt(badOperand);
        } else {
            instructionLoaded = true;
        }
    } else if(instructionRc == ERR_CONFLICT) {
        signalInterrupt(badOperand);
    } else if(instructionRc == ERR_BADRANGE) {
        signalInterrupt(badInstruction);
    }

    return instructionLoaded;
}

// FIXME: Broken function.  Break up into smaller functions
void GenericCPU::nextInstruction() {
    ByteString opcode;
    int decodeRc = ERR_SUCCESS;
    const void * const instructionBase = getInstructionPointer();
    // FIXME: Shouldn't HAVE to be const
    const Instruction *inst;

    do {
        if(readNextByte(opcode, instructionBase))
        {
            signalInterrupt(badOperand);
        } else {
            decodeRc = set.decode(opcode, &inst);
        }
    } while(decodeRc == ERR_CONFLICT || decodeRc == ERR_INCOMPLETE);

    if(decodeRc != ERR_SUCCESS) {
        signalInterrupt(badInstruction);
    } else {
        SizeType operandLength = inst->length;
        SizeType offset = opcode.size();
        ByteString operands;
        if(!readBytes(operands, instructionBase, operandLength)) {
            signalInterrupt(badOperand);
        } else {
            // FIXME: Advance instruction pointer
            // It's import this be done before running the instruction for things like RST to work
            inst->execute(*this, operands);
        }
    }
}<commit_msg>Note the interrupt queue is not emptied in `tick`<commit_after>#include "basecpu.h"
#include "errors.h"
#include "utils.h"

BaseCPU::BaseCPU(const System &sys): sys(sys), running(false) {
}

void BaseCPU::stop() {
    running = false;
}

bool BaseCPU::startup() {
    bool started = false;
    if (!running) {
        running = true;
        started = true;
        reset();
        while(running) { tick(); }
    }
    return started;
}

bool BaseCPU::isRunning() {
    return running;
}

int BaseCPU::readMemory(SizeType offset, SizeType len, void *data) const {
    return sys.readMemory(offset, len, data);
}

int BaseCPU::writeMemory(SizeType offset, SizeType len, const void *data) const {
    return sys.writeMemory(offset, len, data);
}

int BaseCPU::readPort(PortType port, SizeType len, void *data) const {
    return sys.readPort(port, len, data);
}

int BaseCPU::writePort(PortType port, SizeType len, const void *data) const {
    return sys.writePort(port, len, data);
}

void Interruptable::signalInterrupt(Interrupt interrupt) {
    interruptQueue.push(interrupt);
}

SizeType Interruptable::interruptQueueLength() {
    return interruptQueue.size();
}

bool Interruptable::serviceNextInterrupt() {
    bool ret = false;
    if(!interruptQueue.empty()) {
        serviceInterrupt(interruptQueue.front());
        interruptQueue.pop();
        ret = true;
    }
    return ret;
}

GenericCPU::GenericCPU(const System &sys, const InstructionSet &set, Interrupt badInstruction, Interrupt badOperand) :
    BaseCPU(sys), set(set), badInstruction(badInstruction), badOperand(badOperand) {
}

void GenericCPU::tick() {
    // FIXME: Should service the entire interrupt queue (not just the one)
    if(!(interruptsEnabled() && serviceNextInterrupt())) {
        nextInstruction();
    }
}

bool GenericCPU::readBytes(ByteString &buffer, const void * const base, SizeType length) {
    buffer.reserve(length);
    return readMemory((SizeType)base, length, buffer.data()) == ERR_SUCCESS;
}

bool GenericCPU::readNextByte(ByteString &buffer, const void * const base) {
    bool ret = false;
    byte next;
    SizeType nextAddr = ((SizeType)base) + buffer.size();

    if(readMemory(nextAddr, 1, &next) != ERR_SUCCESS) {
        ret = false;
    } else {
        buffer.push_back(next);
        ret = true;
    }
    return ret;
}

int GenericCPU::readInstruction(const void * const instructionBase, const Instruction **out) {
    ByteString opcode;
    bool memoryRc;
    int decodeRc;

    do {
        memoryRc = readNextByte(opcode, instructionBase);
        if(memoryRc) {
            decodeRc = set.decode(opcode, out);
        }
    } while(
        memoryRc && (decodeRc == ERR_CONFLICT || decodeRc == ERR_INCOMPLETE)
    );

    if(!memoryRc) {
        return ERR_CONFLICT;
    }

    if(decodeRc != ERR_SUCCESS) {
        return ERR_BADRANGE;
    } else {
        return ERR_SUCCESS;
    }
}

bool GenericCPU::readInstructionOperands(
    const void * const instructionBase,
    const Instruction &instruction,
    ByteString &operands
) {
    const void * const operandBase = advancePtr(instructionBase, instruction.opcode.size());
    return readBytes(operands, operandBase, instruction.length);
}

bool GenericCPU::loadNextInstruction(const Instruction **instruction, ByteString &operands) {
    bool instructionLoaded = false;
    const void * const instructionBase = getInstructionPointer();
    int instructionRc = readInstruction(instructionBase, instruction);
    if(instructionRc == ERR_SUCCESS) {
        bool operandRc = readInstructionOperands(instructionBase, **instruction, operands);
        if(!operandRc) {
            signalInterrupt(badOperand);
        } else {
            instructionLoaded = true;
        }
    } else if(instructionRc == ERR_CONFLICT) {
        signalInterrupt(badOperand);
    } else if(instructionRc == ERR_BADRANGE) {
        signalInterrupt(badInstruction);
    }

    return instructionLoaded;
}

// FIXME: Broken function.  Break up into smaller functions
void GenericCPU::nextInstruction() {
    ByteString opcode;
    int decodeRc = ERR_SUCCESS;
    const void * const instructionBase = getInstructionPointer();
    // FIXME: Shouldn't HAVE to be const
    const Instruction *inst;

    do {
        if(readNextByte(opcode, instructionBase))
        {
            signalInterrupt(badOperand);
        } else {
            decodeRc = set.decode(opcode, &inst);
        }
    } while(decodeRc == ERR_CONFLICT || decodeRc == ERR_INCOMPLETE);

    if(decodeRc != ERR_SUCCESS) {
        signalInterrupt(badInstruction);
    } else {
        SizeType operandLength = inst->length;
        SizeType offset = opcode.size();
        ByteString operands;
        if(!readBytes(operands, instructionBase, operandLength)) {
            signalInterrupt(badOperand);
        } else {
            // FIXME: Advance instruction pointer
            // It's import this be done before running the instruction for things like RST to work
            inst->execute(*this, operands);
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2010, Camilo Aguilar. Cloudescape, LLC.
#include "bindings.h"

/* size of the event structure, not counting name */
#define EVENT_SIZE  (sizeof (struct inotify_event))

/* reasonable guess as to size of 1024 events */
#define BUF_LEN        (1024 * (EVENT_SIZE + 16))

namespace NodeInotify {
    static Persistent<String> path_sym;
    static Persistent<String> watch_for_sym;
    static Persistent<String> callback_sym;
    static Persistent<String> persistent_sym;
    static Persistent<String> watch_sym;
    static Persistent<String> mask_sym;
    static Persistent<String> cookie_sym;
    static Persistent<String> name_sym;

    void Inotify::Initialize(Handle<Object> target) {
        Local<FunctionTemplate> t = FunctionTemplate::New(Inotify::New);

        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(t, "addWatch",
                                      Inotify::AddWatch);
        NODE_SET_PROTOTYPE_METHOD(t, "removeWatch",
                                      Inotify::RemoveWatch);
        NODE_SET_PROTOTYPE_METHOD(t, "close",
                                      Inotify::Close);

        //Constants initialization
        NODE_DEFINE_CONSTANT(t, IN_ACCESS); //File was accessed (read)
        NODE_DEFINE_CONSTANT(t, IN_ATTRIB); //Metadata changed, e.g., permissions, timestamps,
                                                      //extended attributes, link count (since Linux 2.6.25),
                                                      //UID, GID, etc.
        NODE_DEFINE_CONSTANT(t, IN_CLOSE_WRITE); //File opened for writing was closed
        NODE_DEFINE_CONSTANT(t, IN_CLOSE_NOWRITE); //File not opened for writing was closed
        NODE_DEFINE_CONSTANT(t, IN_CREATE); //File/directory created in watched directory
        NODE_DEFINE_CONSTANT(t, IN_DELETE); //File/directory deleted from watched directory
        NODE_DEFINE_CONSTANT(t, IN_DELETE_SELF); //Watched file/directory was itself deleted
        NODE_DEFINE_CONSTANT(t, IN_MODIFY); //File was modified
        NODE_DEFINE_CONSTANT(t, IN_MOVE_SELF); //Watched file/directory was itself moved
        NODE_DEFINE_CONSTANT(t, IN_MOVED_FROM); //File moved out of watched directory
        NODE_DEFINE_CONSTANT(t, IN_MOVED_TO); //File moved into watched directory
        NODE_DEFINE_CONSTANT(t, IN_OPEN); //File was opened
        NODE_DEFINE_CONSTANT(t, IN_IGNORED); // Watch was removed explicitly (inotify.watch.rm) or
                                                       //automatically (file was deleted, or file system was
                                                        //unmounted)
        NODE_DEFINE_CONSTANT(t, IN_ISDIR); //Subject of this event is a directory
        NODE_DEFINE_CONSTANT(t, IN_Q_OVERFLOW); //Event queue overflowed (wd is -1 for this event)
        NODE_DEFINE_CONSTANT(t, IN_UNMOUNT); //File system containing watched object was unmounted
        NODE_DEFINE_CONSTANT(t, IN_ALL_EVENTS);

        NODE_DEFINE_CONSTANT(t, IN_ONLYDIR); // Only watch the path if it is a directory.
        NODE_DEFINE_CONSTANT(t, IN_DONT_FOLLOW); // Do not follow a sym link
        NODE_DEFINE_CONSTANT(t, IN_ONESHOT); // Only send event once
        NODE_DEFINE_CONSTANT(t, IN_MASK_ADD); //Add (OR) events to watch mask for this pathname if it
                                                        //already exists (instead of replacing mask).

        NODE_DEFINE_CONSTANT(t, IN_CLOSE); // (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)  Close
        NODE_DEFINE_CONSTANT(t, IN_MOVE);  //  (IN_MOVED_FROM | IN_MOVED_TO)  Moves

        path_sym        = NODE_PSYMBOL("path");
        watch_for_sym   = NODE_PSYMBOL("watch_for");
        callback_sym    = NODE_PSYMBOL("callback");
        persistent_sym  = NODE_PSYMBOL("persistent");

        watch_sym       = NODE_PSYMBOL("watch");
        mask_sym        = NODE_PSYMBOL("mask");
        cookie_sym      = NODE_PSYMBOL("cookie");
        name_sym        = NODE_PSYMBOL("name");

        Local<ObjectTemplate> object_tmpl = t->InstanceTemplate();
        object_tmpl->SetAccessor(persistent_sym, Inotify::GetPersistent);

        t->SetClassName(String::NewSymbol("Inotify"));
        target->Set(String::NewSymbol("Inotify"), t->GetFunction());
    }

    Inotify::Inotify() : ObjectWrap() {
        //ev_init(&read_watcher, Inotify::Callback);
        read_watcher = new uv_poll_t;
        read_watcher->data = this;  //preserving my reference to use it inside Inotify::Callback
        //uv_poll_init(uv_default_loop(), &read_watcher, Inotify::Callback);
        persistent = true;
        poll_stopped = 0;
    }

    Inotify::Inotify(bool nonpersistent) : ObjectWrap() {
        read_watcher = new uv_poll_t;
        read_watcher->data = this; //preserving my reference so that we can use it inside Inotify::Callback
        //ev_init(&read_watcher, Inotify::Callback);
        persistent = nonpersistent;
        poll_stopped = 0;
    }

    Inotify::~Inotify() {
        if(!persistent) {
            //ev_ref(EV_DEFAULT_UC);
            uv_ref((uv_handle_t *) read_watcher);
        }
        //ev_io_stop(EV_DEFAULT_UC_ &read_watcher);

        // if Inotify::Close() was already called we do not need to
        // stop polling again thus it causes fail of assertion test
        StopPolling();

        assert(!uv_is_active((uv_handle_t *) read_watcher));
        //assert(!uv_is_pending(&read_watcher));
    }

    Handle<Value> Inotify::New(const Arguments& args) {
        HandleScope scope;

        Inotify *inotify = NULL;
        if(args.Length() == 1 && args[0]->IsBoolean()) {
            inotify = new Inotify(args[0]->IsTrue());
        } else {
            inotify = new Inotify();
        }

 	inotify->fd = inotify_init();

        if(inotify->fd == -1) {
            ThrowException(String::New(strerror(errno)));
            return Null();
        }

	int flags = fcntl(inotify->fd, F_GETFL);
	if(flags == -1) {
	    flags = 0;
	}

	fcntl(inotify->fd, F_SETFL, flags | O_NONBLOCK);

        //ev_io_set(&inotify->read_watcher, inotify->fd, EV_READ);
        //ev_io_start(EV_DEFAULT_UC_ &inotify->read_watcher);
        uv_poll_init(uv_default_loop(), inotify->read_watcher, inotify->fd);
        uv_poll_start(inotify->read_watcher, UV_READABLE, Inotify::Callback);

        Local<Object> obj = args.This();
        inotify->Wrap(obj);

        if(!inotify->persistent) {
            //ev_unref(EV_DEFAULT_UC);
            uv_unref((uv_handle_t *) inotify->read_watcher);
        }
        /**
 	 * Increment object references to avoid be GCed while
   	 * we are waiting for events in the inotify file descriptor.
         * Also, the object is not weak anymore.
	 */
        inotify->Ref();

        return scope.Close(obj);
    }

    Handle<Value> Inotify::AddWatch(const Arguments& args) {
        HandleScope scope;
        uint32_t mask = 0;
        int watch_descriptor = 0;

        if(args.Length() < 1 || !args[0]->IsObject()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify an object as first argument")));
        }

        Local<Object> args_ = args[0]->ToObject();

        if(!args_->Has(path_sym)) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a path to watch for events")));
        }

        if(!args_->Has(callback_sym) ||
            !args_->Get(callback_sym)->IsFunction()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a callback function")));
        }

        if(!args_->Has(watch_for_sym)) {
            mask |= IN_ALL_EVENTS;
        } else {
            if(!args_->Get(watch_for_sym)->IsInt32()) {
                return ThrowException(Exception::TypeError(
                String::New("You must specify OR'ed set of events")));
            }
            mask |= args_->Get(watch_for_sym)->Int32Value();
            if(mask == 0) {
                return ThrowException(Exception::TypeError(
                String::New("You must specify OR'ed set of events")));
            }
       }

        String::Utf8Value path(args_->Get(path_sym));

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());

        /* add watch */
        watch_descriptor = inotify_add_watch(inotify->fd, (const char *) *path, mask);

        Local<Integer> descriptor = Integer::New(watch_descriptor);

        //Local<Function> callback = Local<Function>::Cast(args_->Get(callback_sym));
        inotify->handle_->Set(descriptor, args_->Get(callback_sym));

        return scope.Close(descriptor);
    }

    Handle<Value> Inotify::RemoveWatch(const Arguments& args) {
        HandleScope scope;
        uint32_t watch = 0;
        int ret = -1;

        if(args.Length() == 0 || !args[0]->IsInt32()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a valid watcher descriptor as argument")));
        }
        watch = args[0]->Int32Value();

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());

        ret = inotify_rm_watch(inotify->fd, watch);
        if(ret == -1) {
            ThrowException(String::New(strerror(errno)));
            return False();
        }

        return True();
    }

    void Inotify::on_handle_close(uv_handle_t* handle) {
        assert(!uv_is_active(handle));
        delete handle;
    }

    Handle<Value> Inotify::Close(const Arguments& args) {
        HandleScope scope;
        int ret = -1;

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());
        ret = close(inotify->fd);

        if(ret == -1) {
            ThrowException(String::New(strerror(errno)));
            return False();
        }

        if(!inotify->persistent) {
            //ev_ref(EV_DEFAULT_UC);
            uv_ref((uv_handle_t *) inotify->read_watcher);
        }

        //ev_io_stop(EV_DEFAULT_UC_ &inotify->read_watcher);
        inotify->StopPolling();

        /*Eliminating reference created inside of Inotify::New.
        The object is also weak again.
        Now v8 can do its stuff and GC the object.
        */
        inotify->Unref();

        return True();
    }

    void Inotify::Callback(uv_poll_t *watcher, int status, int revents) {
        HandleScope scope;

        Inotify *inotify = static_cast<Inotify*>(watcher->data);
        assert(watcher == inotify->read_watcher);

        char buffer[BUF_LEN];

        //int length = read(inotify->fd, buffer, BUF_LEN);

        Local<Value> argv[1];
        TryCatch try_catch;

        int i = 0;
	int sz = 0;
        while ((sz = read(inotify->fd, buffer, BUF_LEN)) > 0) {
	  struct inotify_event *event;
	  for (i = 0; i <= (sz-EVENT_SIZE); i += (EVENT_SIZE + event->len)) {
            event = (struct inotify_event *) &buffer[i];

            Local<Object> obj = Object::New();
            obj->Set(watch_sym, Integer::New(event->wd));
            obj->Set(mask_sym, Integer::New(event->mask));
            obj->Set(cookie_sym, Integer::New(event->cookie));

            if(event->len) {
                obj->Set(name_sym, String::New(event->name));
            }
            argv[0] = obj;

            inotify->Ref();
            Local<Value> callback_ = inotify->handle_->Get(Integer::New(event->wd));
            Local<Function> callback = Local<Function>::Cast(callback_);

            callback->Call(inotify->handle_, 1, argv);
            inotify->Unref();

            if(event->mask & IN_IGNORED) {
                //deleting callback because the watch was removed
                Local<Value> wd = Integer::New(event->wd);
                inotify->handle_->Delete(wd->ToString());
            }

            if (try_catch.HasCaught()) {
                FatalException(try_catch);
            }
	  }
	}
    }

    Handle<Value> Inotify::GetPersistent(Local<String> property,
                                        const AccessorInfo& info) {
        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(info.This());

        return inotify->persistent ? True() : False();
     }

    void Inotify::StopPolling() {
        if (!poll_stopped) {
            uv_poll_stop(read_watcher);
            uv_close((uv_handle_t *) read_watcher, Inotify::on_handle_close);
            poll_stopped = 1;
        }
    }

}//namespace NodeInotify
<commit_msg>Remove potentially dangerous assertion from Inotify::~Inotify()<commit_after>// Copyright 2010, Camilo Aguilar. Cloudescape, LLC.
#include "bindings.h"

/* size of the event structure, not counting name */
#define EVENT_SIZE  (sizeof (struct inotify_event))

/* reasonable guess as to size of 1024 events */
#define BUF_LEN        (1024 * (EVENT_SIZE + 16))

namespace NodeInotify {
    static Persistent<String> path_sym;
    static Persistent<String> watch_for_sym;
    static Persistent<String> callback_sym;
    static Persistent<String> persistent_sym;
    static Persistent<String> watch_sym;
    static Persistent<String> mask_sym;
    static Persistent<String> cookie_sym;
    static Persistent<String> name_sym;

    void Inotify::Initialize(Handle<Object> target) {
        Local<FunctionTemplate> t = FunctionTemplate::New(Inotify::New);

        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(t, "addWatch",
                                      Inotify::AddWatch);
        NODE_SET_PROTOTYPE_METHOD(t, "removeWatch",
                                      Inotify::RemoveWatch);
        NODE_SET_PROTOTYPE_METHOD(t, "close",
                                      Inotify::Close);

        //Constants initialization
        NODE_DEFINE_CONSTANT(t, IN_ACCESS); //File was accessed (read)
        NODE_DEFINE_CONSTANT(t, IN_ATTRIB); //Metadata changed, e.g., permissions, timestamps,
                                                      //extended attributes, link count (since Linux 2.6.25),
                                                      //UID, GID, etc.
        NODE_DEFINE_CONSTANT(t, IN_CLOSE_WRITE); //File opened for writing was closed
        NODE_DEFINE_CONSTANT(t, IN_CLOSE_NOWRITE); //File not opened for writing was closed
        NODE_DEFINE_CONSTANT(t, IN_CREATE); //File/directory created in watched directory
        NODE_DEFINE_CONSTANT(t, IN_DELETE); //File/directory deleted from watched directory
        NODE_DEFINE_CONSTANT(t, IN_DELETE_SELF); //Watched file/directory was itself deleted
        NODE_DEFINE_CONSTANT(t, IN_MODIFY); //File was modified
        NODE_DEFINE_CONSTANT(t, IN_MOVE_SELF); //Watched file/directory was itself moved
        NODE_DEFINE_CONSTANT(t, IN_MOVED_FROM); //File moved out of watched directory
        NODE_DEFINE_CONSTANT(t, IN_MOVED_TO); //File moved into watched directory
        NODE_DEFINE_CONSTANT(t, IN_OPEN); //File was opened
        NODE_DEFINE_CONSTANT(t, IN_IGNORED); // Watch was removed explicitly (inotify.watch.rm) or
                                                       //automatically (file was deleted, or file system was
                                                        //unmounted)
        NODE_DEFINE_CONSTANT(t, IN_ISDIR); //Subject of this event is a directory
        NODE_DEFINE_CONSTANT(t, IN_Q_OVERFLOW); //Event queue overflowed (wd is -1 for this event)
        NODE_DEFINE_CONSTANT(t, IN_UNMOUNT); //File system containing watched object was unmounted
        NODE_DEFINE_CONSTANT(t, IN_ALL_EVENTS);

        NODE_DEFINE_CONSTANT(t, IN_ONLYDIR); // Only watch the path if it is a directory.
        NODE_DEFINE_CONSTANT(t, IN_DONT_FOLLOW); // Do not follow a sym link
        NODE_DEFINE_CONSTANT(t, IN_ONESHOT); // Only send event once
        NODE_DEFINE_CONSTANT(t, IN_MASK_ADD); //Add (OR) events to watch mask for this pathname if it
                                                        //already exists (instead of replacing mask).

        NODE_DEFINE_CONSTANT(t, IN_CLOSE); // (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)  Close
        NODE_DEFINE_CONSTANT(t, IN_MOVE);  //  (IN_MOVED_FROM | IN_MOVED_TO)  Moves

        path_sym        = NODE_PSYMBOL("path");
        watch_for_sym   = NODE_PSYMBOL("watch_for");
        callback_sym    = NODE_PSYMBOL("callback");
        persistent_sym  = NODE_PSYMBOL("persistent");

        watch_sym       = NODE_PSYMBOL("watch");
        mask_sym        = NODE_PSYMBOL("mask");
        cookie_sym      = NODE_PSYMBOL("cookie");
        name_sym        = NODE_PSYMBOL("name");

        Local<ObjectTemplate> object_tmpl = t->InstanceTemplate();
        object_tmpl->SetAccessor(persistent_sym, Inotify::GetPersistent);

        t->SetClassName(String::NewSymbol("Inotify"));
        target->Set(String::NewSymbol("Inotify"), t->GetFunction());
    }

    Inotify::Inotify() : ObjectWrap() {
        //ev_init(&read_watcher, Inotify::Callback);
        read_watcher = new uv_poll_t;
        read_watcher->data = this;  //preserving my reference to use it inside Inotify::Callback
        //uv_poll_init(uv_default_loop(), &read_watcher, Inotify::Callback);
        persistent = true;
        poll_stopped = 0;
    }

    Inotify::Inotify(bool nonpersistent) : ObjectWrap() {
        read_watcher = new uv_poll_t;
        read_watcher->data = this; //preserving my reference so that we can use it inside Inotify::Callback
        //ev_init(&read_watcher, Inotify::Callback);
        persistent = nonpersistent;
        poll_stopped = 0;
    }

    Inotify::~Inotify() {
        if(!persistent) {
            //ev_ref(EV_DEFAULT_UC);
            uv_ref((uv_handle_t *) read_watcher);
        }
        //ev_io_stop(EV_DEFAULT_UC_ &read_watcher);

        // if Inotify::Close() was already called we do not need to
        // stop polling again thus it causes fail of assertion test
        StopPolling();

        //assert(!uv_is_pending(&read_watcher));
    }

    Handle<Value> Inotify::New(const Arguments& args) {
        HandleScope scope;

        Inotify *inotify = NULL;
        if(args.Length() == 1 && args[0]->IsBoolean()) {
            inotify = new Inotify(args[0]->IsTrue());
        } else {
            inotify = new Inotify();
        }

 	inotify->fd = inotify_init();

        if(inotify->fd == -1) {
            ThrowException(String::New(strerror(errno)));
            return Null();
        }

	int flags = fcntl(inotify->fd, F_GETFL);
	if(flags == -1) {
	    flags = 0;
	}

	fcntl(inotify->fd, F_SETFL, flags | O_NONBLOCK);

        //ev_io_set(&inotify->read_watcher, inotify->fd, EV_READ);
        //ev_io_start(EV_DEFAULT_UC_ &inotify->read_watcher);
        uv_poll_init(uv_default_loop(), inotify->read_watcher, inotify->fd);
        uv_poll_start(inotify->read_watcher, UV_READABLE, Inotify::Callback);

        Local<Object> obj = args.This();
        inotify->Wrap(obj);

        if(!inotify->persistent) {
            //ev_unref(EV_DEFAULT_UC);
            uv_unref((uv_handle_t *) inotify->read_watcher);
        }
        /**
 	 * Increment object references to avoid be GCed while
   	 * we are waiting for events in the inotify file descriptor.
         * Also, the object is not weak anymore.
	 */
        inotify->Ref();

        return scope.Close(obj);
    }

    Handle<Value> Inotify::AddWatch(const Arguments& args) {
        HandleScope scope;
        uint32_t mask = 0;
        int watch_descriptor = 0;

        if(args.Length() < 1 || !args[0]->IsObject()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify an object as first argument")));
        }

        Local<Object> args_ = args[0]->ToObject();

        if(!args_->Has(path_sym)) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a path to watch for events")));
        }

        if(!args_->Has(callback_sym) ||
            !args_->Get(callback_sym)->IsFunction()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a callback function")));
        }

        if(!args_->Has(watch_for_sym)) {
            mask |= IN_ALL_EVENTS;
        } else {
            if(!args_->Get(watch_for_sym)->IsInt32()) {
                return ThrowException(Exception::TypeError(
                String::New("You must specify OR'ed set of events")));
            }
            mask |= args_->Get(watch_for_sym)->Int32Value();
            if(mask == 0) {
                return ThrowException(Exception::TypeError(
                String::New("You must specify OR'ed set of events")));
            }
       }

        String::Utf8Value path(args_->Get(path_sym));

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());

        /* add watch */
        watch_descriptor = inotify_add_watch(inotify->fd, (const char *) *path, mask);

        Local<Integer> descriptor = Integer::New(watch_descriptor);

        //Local<Function> callback = Local<Function>::Cast(args_->Get(callback_sym));
        inotify->handle_->Set(descriptor, args_->Get(callback_sym));

        return scope.Close(descriptor);
    }

    Handle<Value> Inotify::RemoveWatch(const Arguments& args) {
        HandleScope scope;
        uint32_t watch = 0;
        int ret = -1;

        if(args.Length() == 0 || !args[0]->IsInt32()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a valid watcher descriptor as argument")));
        }
        watch = args[0]->Int32Value();

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());

        ret = inotify_rm_watch(inotify->fd, watch);
        if(ret == -1) {
            ThrowException(String::New(strerror(errno)));
            return False();
        }

        return True();
    }

    void Inotify::on_handle_close(uv_handle_t* handle) {
        assert(!uv_is_active(handle));
        delete handle;
    }

    Handle<Value> Inotify::Close(const Arguments& args) {
        HandleScope scope;
        int ret = -1;

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());
        ret = close(inotify->fd);

        if(ret == -1) {
            ThrowException(String::New(strerror(errno)));
            return False();
        }

        if(!inotify->persistent) {
            //ev_ref(EV_DEFAULT_UC);
            uv_ref((uv_handle_t *) inotify->read_watcher);
        }

        //ev_io_stop(EV_DEFAULT_UC_ &inotify->read_watcher);
        inotify->StopPolling();

        /*Eliminating reference created inside of Inotify::New.
        The object is also weak again.
        Now v8 can do its stuff and GC the object.
        */
        inotify->Unref();

        return True();
    }

    void Inotify::Callback(uv_poll_t *watcher, int status, int revents) {
        HandleScope scope;

        Inotify *inotify = static_cast<Inotify*>(watcher->data);
        assert(watcher == inotify->read_watcher);

        char buffer[BUF_LEN];

        //int length = read(inotify->fd, buffer, BUF_LEN);

        Local<Value> argv[1];
        TryCatch try_catch;

        int i = 0;
	int sz = 0;
        while ((sz = read(inotify->fd, buffer, BUF_LEN)) > 0) {
	  struct inotify_event *event;
	  for (i = 0; i <= (sz-EVENT_SIZE); i += (EVENT_SIZE + event->len)) {
            event = (struct inotify_event *) &buffer[i];

            Local<Object> obj = Object::New();
            obj->Set(watch_sym, Integer::New(event->wd));
            obj->Set(mask_sym, Integer::New(event->mask));
            obj->Set(cookie_sym, Integer::New(event->cookie));

            if(event->len) {
                obj->Set(name_sym, String::New(event->name));
            }
            argv[0] = obj;

            inotify->Ref();
            Local<Value> callback_ = inotify->handle_->Get(Integer::New(event->wd));
            Local<Function> callback = Local<Function>::Cast(callback_);

            callback->Call(inotify->handle_, 1, argv);
            inotify->Unref();

            if(event->mask & IN_IGNORED) {
                //deleting callback because the watch was removed
                Local<Value> wd = Integer::New(event->wd);
                inotify->handle_->Delete(wd->ToString());
            }

            if (try_catch.HasCaught()) {
                FatalException(try_catch);
            }
	  }
	}
    }

    Handle<Value> Inotify::GetPersistent(Local<String> property,
                                        const AccessorInfo& info) {
        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(info.This());

        return inotify->persistent ? True() : False();
     }

    void Inotify::StopPolling() {
        if (!poll_stopped) {
            uv_poll_stop(read_watcher);
            uv_close((uv_handle_t *) read_watcher, Inotify::on_handle_close);
            poll_stopped = 1;
        }
    }

}//namespace NodeInotify
<|endoftext|>