Compare commits

...

25 Commits

Author SHA1 Message Date
3535cfc13b add command and attribute info to DeviceProxy 2023-02-09 02:26:47 +01:00
9bd078b221 simplify attribute info handling 2023-02-09 01:22:59 +01:00
1338eae773 add attribute and command info cache to DeviceProxy 2023-02-08 20:18:05 +01:00
59fb9aa2b3 add licensing information to README 2023-02-07 21:36:56 +01:00
5d527bc7f7 add LICENSE 2023-02-07 21:34:24 +01:00
5c829d936f add attribute info to AttributeProxy 2023-02-07 18:48:06 +01:00
b0be10e25d remove unused pop_number template 2023-02-06 22:34:07 +01:00
7d379fd5dd unify Tango types conversion 2023-02-06 22:16:13 +01:00
6cf75b0da6 add Lua 5.2 and 5.3 support 2023-02-05 22:34:21 +01:00
71673c8ede add notice to files 2023-02-05 18:24:12 +01:00
361e3abead add AttributeProxy support 2023-02-05 13:42:37 +01:00
152734b329 improve error handling 2023-02-05 12:53:11 +01:00
69143b963b add error handling 2023-02-05 01:34:46 +01:00
a93c8292f1 add DevState support 2023-02-04 20:20:35 +01:00
b07072a5a8 better read attributes test script 2023-02-04 17:05:03 +01:00
fe640b0ae0 use type names instead of IDs 2023-02-04 15:05:07 +01:00
ccf52c63ea implement more command data types 2023-02-04 14:18:40 +01:00
619c05fc0d add project files to .gitignore 2023-02-04 00:29:15 +01:00
5f138b362b fix stack indexes 2023-02-04 00:20:09 +01:00
0d667035d3 add README 2023-02-03 23:09:12 +01:00
2459ea8757 add rudimentary testing scripts 2023-02-03 22:02:34 +01:00
7e942585af add command support, refactor attr data handling 2023-02-03 22:00:26 +01:00
22ef574220 rename attrtype -> attrdata 2023-02-03 17:25:36 +01:00
c4c42404eb add lua and cpp versions 2023-02-03 17:21:17 +01:00
d9a4685c1f initial DeviceProxy read/write implementation 2023-02-02 23:21:39 +01:00
51 changed files with 2965 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.sublime-project
*.sublime-workspace
build/*
lib/*
tmp/*

21
LICENSE Normal file
View File

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

65
Makefile Normal file
View File

@ -0,0 +1,65 @@
#------------------------------------------------------------------------------
#
# luTango - Lua binding for Tango
#
# Copyright (C) 2023 Grzegorz Kowalski
# See LICENSE for legal information
#
# file: Makefile
#
# Build configuration
#
#------------------------------------------------------------------------------
VERSION=$(shell git describe --tags --always --dirty)\:$(shell date +'%Y%m%d')
SRC_DIR := src
BUILD_DIR := build
OUT_DIR := lib
ifeq ($(LUA_VERSION),)
LUA_VERSION := 5.1
endif
ifeq ($(PREFIX),)
PREFIX := /usr/local/lib/lua/$(LUA_VERSION)/lutango
endif
LUT_INCLUDE := $(SRC_DIR)
SRCS := $(shell find . -name '*.cpp')
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
SONAME := core.so.$(VERSION)
SOLINK := core.so
CC = g++
CXX = $(CC)
CFLAGS = -shared -fpic -D_REENTRANT -DVERSION=\"$(VERSION)\" -I$(LUT_INCLUDE) -Wl,--no-undefined
CFLAGS += $(shell pkg-config --cflags tango lua$(LUA_VERSION))
LDFLAGS = $(shell pkg-config --libs tango lua$(LUA_VERSION))
CPPFLAGS += $(CFLAGS)
dir-guard=@mkdir -p $(@D)
.PHONY: default clean install
default: $(OUT_DIR)/$(SONAME)
$(OUT_DIR)/$(SONAME): $(OBJS)
$(dir-guard)
$(CXX) $^ $(CPPFLAGS) $(LDFLAGS) -o $@
$(BUILD_DIR)/%.cpp.o: %.cpp
$(dir-guard)
$(CXX) $(CPPFLAGS) -c $< -o $@
clean:
rm -rf build
rm -rf lib
install:
install -d $(PREFIX)
install -m 644 $(SRC_DIR)/*.lua $(PREFIX)
install -s -m 644 $(OUT_DIR)/$(SONAME) $(PREFIX)
ln -sf $(PREFIX)/$(SONAME) $(PREFIX)/$(SOLINK)

10
README.md Normal file
View File

@ -0,0 +1,10 @@
# luTango - Lua binding for Tango
luTango is a module providing access to [Tango Control System](https://www.tango-controls.org/) with Lua.
In it's current state, a basic subset of client API is available (DeviceProxy, AttributeProxy), although not all Tango types are supported.
The library has been tested with Lua 5.1, 5.2 and 5.3.
---
luTango is distributed under terms of MIT License. Please see LICENSE file for details.

19
src/core/global.h Normal file
View File

@ -0,0 +1,19 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: global.h
//
// Global values
//
//-----------------------------------------------------------------------------
#ifndef __GLOBAL_H__
# define __GLOBAL_H__
#define LUTANGO "lutango"
#endif /* __GLOBAL_H__ */

47
src/core/logging/log.cpp Normal file
View File

@ -0,0 +1,47 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: log.cpp
//
// Logging facilities for core
//
//-----------------------------------------------------------------------------
#include "log.h"
void _log(LogLevel level, const char* fmt, const char* _file, const char* _func, int _line, ...)
{
if(level <= current_log_level)
{
va_list args;
va_start(args, _line);
fprintf(stderr, "[%s]@[CORE:%s:%s:%d]: ", LogLevelLabels[level], _file, _func, _line);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
}
}
void set_log_level(LogLevel level)
{
current_log_level = level;
}
void lut_lua_register_log(lua_State* L)
{
lua_newtable(L);
va_lua_register(L, lut_log);
lua_setfield(L, -2, "log");
LUT_LOG(INFO, "Registered log table");
}
int lut_log_set_log_level(lua_State* L)
{
int level = luaL_checknumber(L, 1);
set_log_level((LogLevel)level);
return 1;
}

52
src/core/logging/log.h Normal file
View File

@ -0,0 +1,52 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: log.h
//
// Logging facilities for core
//
//-----------------------------------------------------------------------------
#ifndef __LOG_H__
# define __LOG_H__
#include <stdio.h>
#include <stdarg.h>
#include <core/lua.h>
#include <core/lua/version_agnostic.h>
#define LUT_LOG(level, msg, ...) _log(level, msg, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
typedef enum _LogLevel
{
CRITICAL = 0,
ERROR,
WARNING,
INFO,
DEBUG,
TRACE
} LogLevel;
static const char* LogLevelLabels[] = {"CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE"};
static LogLevel current_log_level = WARNING;
// C API
void _log(LogLevel level, const char* fmt, const char* _file, const char* _func, int _line, ...);
void set_log_level(LogLevel level);
// Lua API
void lut_lua_register_log(lua_State* L);
int lut_log_set_log_level(lua_State* L);
static const luaL_Reg lut_log[] =
{
{ "set_log_level", lut_log_set_log_level },
{ NULL, NULL }
};
#endif /* __LOG_H__ */

29
src/core/lua.h Normal file
View File

@ -0,0 +1,29 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lua.h
//
// Lua includes
//
//-----------------------------------------------------------------------------
#ifndef __LUA_INCLUDES_H__
# define __LUA_INCLUDES_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <lua.h>
#include <lauxlib.h>
#ifdef __cplusplus
}
#endif
#endif /* __LUA_INCLUDES_H__ */

21
src/core/lua/load.cpp Normal file
View File

@ -0,0 +1,21 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: load.cpp
//
// Facilities for loading Lua code into core
//
//-----------------------------------------------------------------------------
#include "load.h"
void load_lua_lib(lua_State* L, const char* name)
{
lua_getglobal(L, "require");
lua_pushstring(L, name);
lua_call(L, 1, 1);
}

21
src/core/lua/load.h Normal file
View File

@ -0,0 +1,21 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: load.h
//
// Facilities for loading Lua code into core
//
//-----------------------------------------------------------------------------
#ifndef __LOAD_H__
# define __LOAD_H__
#include <core/lua.h>
void load_lua_lib(lua_State* L, const char* name);
#endif /* __LOAD_H__ */

21
src/core/lua/object.cpp Normal file
View File

@ -0,0 +1,21 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: object.cpp
//
// Lua objects manipulation in C++
//
//-----------------------------------------------------------------------------
#include "object.h"
void *lut_getobj(lua_State *L, int idx)
{
LUT_LOG(TRACE, "Extracting object from userdata");
return *(void**)lua_touserdata(L, idx);
}

22
src/core/lua/object.h Normal file
View File

@ -0,0 +1,22 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: object.h
//
// Lua objects manipulation in C++
//
//-----------------------------------------------------------------------------
#ifndef __OBJECT_H__
# define __OBJECT_H__
#include <core/lua.h>
#include <core/logging/log.h>
void *lut_getobj(lua_State *L, int idx);
#endif /* __OBJECT_H__ */

64
src/core/lua/stack.cpp Normal file
View File

@ -0,0 +1,64 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: stack.cpp
//
// Lua stack manipulation
//
//-----------------------------------------------------------------------------
#include "stack.h"
void push_bool_table(lua_State* L, std::vector<bool> v)
{
lua_newtable(L);
for(int i = 0; i < v.size(); i++)
{
lua_pushboolean(L, v[i]);
lua_rawseti(L, -2, i+1);
}
}
void push_string_table(lua_State* L, std::vector<std::string> v)
{
lua_newtable(L);
for(int i = 0; i < v.size(); i++)
{
lua_pushstring(L, v[i].c_str());
lua_rawseti(L, -2, i+1);
}
}
std::vector<bool> pop_bool_table(lua_State* L, int idx)
{
LUT_LOG(TRACE, "Popping boolean table from stack");
std::vector<bool> v;
lua_settop(L, idx);
for(int i = 1; i <= va_lua_objlen(L, idx); i++)
{
lua_rawgeti(L, idx, i);
bool vi = lua_toboolean(L, idx+1);
v.push_back(vi);
lua_settop(L, idx);
}
return v;
}
std::vector<std::string> pop_string_table(lua_State* L, int idx)
{
LUT_LOG(TRACE, "Popping string table from stack");
std::vector<std::string> v;
lua_settop(L, idx);
for(int i = 1; i <= va_lua_objlen(L, idx); i++)
{
lua_rawgeti(L, idx, i);
std::string vi = luaL_checkstring(L, idx+1);
v.push_back(vi);
lua_settop(L, idx);
}
return v;
}

59
src/core/lua/stack.h Normal file
View File

@ -0,0 +1,59 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: stack.h
//
// Lua stack manipulation
//
//-----------------------------------------------------------------------------
#ifndef __STACK_H__
# define __STACK_H__
#include <string>
#include <vector>
#include <core/lua.h>
#include <core/lua/version_agnostic.h>
#include <core/logging/log.h>
void push_bool_table(lua_State* L, std::vector<bool> value);
void push_string_table(lua_State* L, std::vector<std::string> value);
std::vector<bool> pop_bool_table(lua_State* L, int idx);
std::vector<std::string> pop_string_table(lua_State* L, int idx);
// CPP: non-specialized templates must be implemented in header file
template<class T>
void push_number_table(lua_State* L, std::vector<T> v)
{
lua_newtable(L);
for(int i = 0; i < v.size(); i++)
{
lua_pushnumber(L, v[i]);
lua_rawseti(L, -2, i+1);
}
}
template<class T>
std::vector<T> pop_number_table(lua_State* L, int idx)
{
LUT_LOG(TRACE, "Popping number table from stack");
std::vector<T> v;
lua_settop(L, idx);
for(int i = 1; i <= va_lua_objlen(L, idx); i++)
{
lua_rawgeti(L, idx, i);
T vi = luaL_checknumber(L, idx+1);
v.push_back(vi);
lua_settop(L, idx);
}
return v;
}
#endif /* __STACK_H__ */

View File

@ -0,0 +1,25 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: version_agnostic.cpp
//
// Facilitate different versions of Lua
//
//-----------------------------------------------------------------------------
#include "version_agnostic.h"
void va_lua_register(lua_State* L, const luaL_Reg* reg)
{
# if (LUA_VERSION_NUM > 501)
// Lua > 5.1
luaL_setfuncs(L, reg, 0);
# else
// Lua 5.1
luaL_register(L, NULL, reg);
# endif
}

View File

@ -0,0 +1,29 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: version_agnostic.h
//
// Facilitate different versions of Lua
//
//-----------------------------------------------------------------------------
#ifndef __VERSION_AGNOSTIC_H__
# define __VERSION_AGNOSTIC_H__
#include <core/lua.h>
#if (LUA_VERSION_NUM > 501)
// Lua > 5.1
# define va_lua_objlen lua_rawlen
#else
// Lua 5.1
# define va_lua_objlen lua_objlen
#endif
void va_lua_register(lua_State* L, const luaL_Reg* reg);
#endif /* __VERSION_AGNOSTIC_H__ */

39
src/core/lutango_core.cpp Normal file
View File

@ -0,0 +1,39 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lutango_core.cpp
//
// Core module entry point
//
//-----------------------------------------------------------------------------
#include "lutango_core.h"
#ifdef __cplusplus
extern "C"
{
#endif
int luaopen_lutango_core(lua_State* L)
{
LUT_LOG(TRACE, "luTango core open.");
LUT_LOG(INFO, "luTango core v%s", VERSION);
lua_newtable(L);
lut_lua_register_log(L);
lut_lua_register_sys(L);
lut_lua_register_DeviceProxy(L);
lut_lua_register_AttributeProxy(L);
LUT_LOG(TRACE, "Core module table registered.");
return 1;
}
#ifdef __cplusplus
}
#endif

38
src/core/lutango_core.h Normal file
View File

@ -0,0 +1,38 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lutango_core.h
//
// Core module entry point
//
//-----------------------------------------------------------------------------
#ifndef __LUTANGO_H__
# define __LUTANGO_H__
//-----------------------------------------------------------------------------
#include <core/lua.h>
#include <core/logging/log.h>
#include <core/sys/sys.h>
#include <core/tango/DeviceProxy/lut_DeviceProxy.h>
#include <core/tango/AttributeProxy/lut_AttributeProxy.h>
#ifdef __cplusplus
extern "C"
{
#endif
// core is loaded as "lutango.core"
int luaopen_lutango_core(lua_State* L);
#ifdef __cplusplus
}
#endif
//-----------------------------------------------------------------------------
#endif /* __LUTANGO_H__ */

47
src/core/sys/sys.cpp Normal file
View File

@ -0,0 +1,47 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: sys.cpp
//
// System utilities
//
//-----------------------------------------------------------------------------
#include "sys.h"
void lut_lua_register_sys(lua_State* L)
{
lua_newtable(L);
va_lua_register(L, lut_sys);
lua_setfield(L, -2, "sys");
LUT_LOG(INFO, "Registered sys table");
}
int lut_sys_version(lua_State* L)
{
lua_pushstring(L, VERSION);
return 1;
}
int lut_sys_tango_version(lua_State* L)
{
lua_pushstring(L, Tango::TgLibVers);
return 1;
}
int lut_sys_cpp_version(lua_State* L)
{
std::ostringstream cpp_ver;
#ifdef __clang__
cpp_ver << "clang++ " << __clang_major__ << "." << __clang_minor__ << "." << __clang_patchlevel__;
#else
cpp_ver << "GCC " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__;
#endif
lua_pushstring(L, cpp_ver.str().c_str());
return 1;
}

36
src/core/sys/sys.h Normal file
View File

@ -0,0 +1,36 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: sys.h
//
// System utilities
//
//-----------------------------------------------------------------------------
#ifndef __SYS_H__
# define __SYS_H__
#include <core/lua.h>
#include <core/tango.h>
#include <core/logging/log.h>
#include <core/lua/version_agnostic.h>
// Lua API
void lut_lua_register_sys(lua_State* L);
int lut_sys_version(lua_State* L);
int lut_sys_tango_version(lua_State* L);
int lut_sys_cpp_version(lua_State* L);
static const luaL_Reg lut_sys[] =
{
{ "version", lut_sys_version },
{ "tango_version", lut_sys_tango_version },
{ "cpp_version", lut_sys_cpp_version },
{ NULL, NULL }
};
#endif /* __SYS_H__ */

27
src/core/tango.h Normal file
View File

@ -0,0 +1,27 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: tango.h
//
// Tango includes
//
//-----------------------------------------------------------------------------
#ifndef __TANGO_INCLUDES_H__
# define __TANGO_INCLUDES_H__
#include <tango/tango.h>
namespace lut_Tango
{
static const char* DispLevelNames[] = {"OPERATOR", "EXPERT", "DL_UNKNOWN"};
static const char* AttrDataFormatNames[] = {"SCALAR", "SPECTRUM", "IMAGE", "FMT_UNKNOWN"};
static const char* AttrMemorizedTypeNames[] = {"NOT_KNOWN", "NONE", "MEMORIZED", "MEMORIZED_WRITE_INIT"};
static const char* AttrWriteTypeNames[] = {"READ", "READ_WITH_WRITE", "WRITE", "READ_WRITE", "WT_UNKNOWN"};
}
#endif /* __TANGO_INCLUDES_H__ */

View File

@ -0,0 +1,282 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_AttrCmdInfo.cpp
//
// Bindings for AttributeInfoEx and CommandInfo classes
//
//-----------------------------------------------------------------------------
#include "lut_AttrCmdInfo.h"
void lut_AttributeInfo(lua_State* L, Tango::AttributeInfoEx info)
{
lua_createtable(L, 0, 25);
int top = lua_gettop(L);
lut_AttributeAlarmInfo(L, info.alarms);
lua_setfield(L, top, "alarms");
push_string_table(L, info.enum_labels);
lua_setfield(L, top, "enum_labels");
lua_createtable(L, 3, 0);
int events_top = lua_gettop(L);
lut_ArchiveEventInfo(L, info.events.arch_event);
lua_setfield(L, events_top, "archive_event");
lut_ChangeEventInfo(L, info.events.ch_event);
lua_setfield(L, events_top, "change_event");
lut_PeriodicEventInfo(L, info.events.per_event);
lua_setfield(L, events_top, "periodic_event");
lua_setfield(L, top, "events");
lua_pushstring(L, lut_Tango::AttrMemorizedTypeNames[info.memorized]);
lua_setfield(L, top, "memorized");
lua_pushstring(L, info.root_attr_name.c_str());
lua_setfield(L, top, "root_attr_name");
lua_pushstring(L, lut_Tango::DispLevelNames[info.disp_level]);
lua_setfield(L, top, "disp_level");
lua_pushstring(L, lut_Tango::AttrDataFormatNames[info.data_format]);
lua_setfield(L, top, "data_format");
lua_pushstring(L, Tango::CmdArgTypeName[info.data_type]);
lua_setfield(L, top, "tango_type");
lua_pushstring(L, to_lua_type_name(info.data_type).c_str());
lua_setfield(L, top, "data_type");
lua_pushstring(L, info.description.c_str());
lua_setfield(L, top, "description");
lua_pushstring(L, info.display_unit.c_str());
lua_setfield(L, top, "display_unit");
lua_pushstring(L, info.format.c_str());
lua_setfield(L, top, "format");
lua_pushstring(L, info.label.c_str());
lua_setfield(L, top, "label");
lua_pushstring(L, info.max_alarm.c_str());
lua_setfield(L, top, "max_alarm");
lua_pushstring(L, info.min_alarm.c_str());
lua_setfield(L, top, "min_alarm");
lua_pushstring(L, info.max_value.c_str());
lua_setfield(L, top, "max_value");
lua_pushstring(L, info.min_value.c_str());
lua_setfield(L, top, "min_value");
lua_pushnumber(L, info.max_dim_x);
lua_setfield(L, top, "max_dim_x");
lua_pushnumber(L, info.max_dim_y);
lua_setfield(L, top, "max_dim_y");
lua_pushstring(L, info.name.c_str());
lua_setfield(L, top, "name");
lua_pushstring(L, info.standard_unit.c_str());
lua_setfield(L, top, "standard_unit");
lua_pushstring(L, info.unit.c_str());
lua_setfield(L, top, "unit");
lua_pushstring(L, lut_Tango::AttrWriteTypeNames[info.writable]);
lua_setfield(L, top, "writable");
lua_pushstring(L, info.writable_attr_name.c_str());
lua_setfield(L, top, "writable_attr_name");
push_string_table(L, info.extensions);
lua_setfield(L, top, "extensions");
push_string_table(L, info.sys_extensions);
lua_setfield(L, top, "sys_extensions");
}
void lut_CommandInfo(lua_State* L, Tango::CommandInfo info)
{
lua_createtable(L, 0, 9);
int top = lua_gettop(L);
lua_pushstring(L, lut_Tango::DispLevelNames[info.disp_level]);
lua_setfield(L, top, "disp_level");
lua_pushstring(L, info.cmd_name.c_str());
lua_setfield(L, top, "cmd_name");
lua_pushnumber(L, info.cmd_tag);
lua_setfield(L, top, "cmd_tag");
lua_pushstring(L, to_lua_type_name(info.in_type).c_str());
lua_setfield(L, top, "in_type");
lua_pushstring(L, Tango::CmdArgTypeName[info.in_type]);
lua_setfield(L, top, "in_tango_type");
lua_pushstring(L, info.in_type_desc.c_str());
lua_setfield(L, top, "in_type_desc");
lua_pushstring(L, to_lua_type_name(info.out_type).c_str());
lua_setfield(L, top, "out_type");
lua_pushstring(L, Tango::CmdArgTypeName[info.out_type]);
lua_setfield(L, top, "out_tango_type");
lua_pushstring(L, info.out_type_desc.c_str());
lua_setfield(L, top, "out_type_desc");
}
void lut_AttributeAlarmInfo(lua_State* L, Tango::AttributeAlarmInfo info)
{
lua_createtable(L, 0, 7);
int top = lua_gettop(L);
lua_pushstring(L, info.delta_t.c_str());
lua_setfield(L, top, "delta_t");
lua_pushstring(L, info.delta_val.c_str());
lua_setfield(L, top, "delta_val");
lua_pushstring(L, info.max_alarm.c_str());
lua_setfield(L, top, "max_alarm");
lua_pushstring(L, info.max_warning.c_str());
lua_setfield(L, top, "max_warning");
lua_pushstring(L, info.min_alarm.c_str());
lua_setfield(L, top, "min_alarm");
lua_pushstring(L, info.min_warning.c_str());
lua_setfield(L, top, "min_warning");
push_string_table(L, info.extensions);
lua_setfield(L, top, "extensions");
}
void lut_ArchiveEventInfo(lua_State* L, Tango::ArchiveEventInfo info)
{
lua_createtable(L, 0, 4);
int top = lua_gettop(L);
lua_pushstring(L, info.archive_abs_change.c_str());
lua_setfield(L, top, "archive_abs_change");
lua_pushstring(L, info.archive_period.c_str());
lua_setfield(L, top, "archive_period");
lua_pushstring(L, info.archive_rel_change.c_str());
lua_setfield(L, top, "archive_rel_change");
push_string_table(L, info.extensions);
lua_setfield(L, top, "extensions");
}
void lut_ChangeEventInfo(lua_State* L, Tango::ChangeEventInfo info)
{
lua_createtable(L, 0, 3);
int top = lua_gettop(L);
lua_pushstring(L, info.abs_change.c_str());
lua_setfield(L, top, "abs_change");
lua_pushstring(L, info.rel_change.c_str());
lua_setfield(L, top, "rel_change");
push_string_table(L, info.extensions);
lua_setfield(L, top, "extensions");
}
void lut_PeriodicEventInfo(lua_State* L, Tango::PeriodicEventInfo info)
{
lua_createtable(L, 0, 2);
int top = lua_gettop(L);
lua_pushstring(L, info.period.c_str());
lua_setfield(L, top, "period");
push_string_table(L, info.extensions);
lua_setfield(L, top, "extensions");
}
std::string to_lua_type_name(int type)
{
std::string type_name;
switch(type)
{
case Tango::DEV_VOID: // 0 - void
type_name = "nil";
break;
case Tango::DEV_BOOLEAN: // 1 - bool
type_name = "boolean";
break;
case Tango::DEV_SHORT: // 2 - short
case Tango::DEV_LONG: // 3 - long
case Tango::DEV_FLOAT: // 4 - float
case Tango::DEV_DOUBLE: // 5 - double
case Tango::DEV_USHORT: // 6 - ushort
case Tango::DEV_ULONG: // 7 - ulong
case Tango::DEV_LONG64: // 23 - long64
case Tango::DEV_ULONG64: // 24 - ulong64
case Tango::DEV_INT: // 27 - int
type_name = "number";
break;
case Tango::DEV_STRING: // 8 - string
case Tango::DEVVAR_CHARARRAY: // 9 - char[]
case Tango::CONST_DEV_STRING: // 20 - const string
case Tango::DEV_UCHAR: // 22 - uchar
type_name = "string";
break;
case Tango::DEVVAR_SHORTARRAY: // 10 - short[]
case Tango::DEVVAR_LONGARRAY: // 11 - long[]
case Tango::DEVVAR_FLOATARRAY: // 12 - float[]
case Tango::DEVVAR_DOUBLEARRAY: // 13 - double[]
case Tango::DEVVAR_USHORTARRAY: // 14 - ushort[]
case Tango::DEVVAR_ULONGARRAY: // 15 - ulong[]
case Tango::DEVVAR_LONG64ARRAY: // 25 - long64[]
case Tango::DEVVAR_ULONG64ARRAY: // 26 - ulong64[]
type_name = "table(number)";
break;
case Tango::DEVVAR_STRINGARRAY: // 16 - string[]
type_name = "table(string)";
break;
case Tango::DEV_STATE: // 19 - DevState
type_name = "DevState";
break;
case Tango::DEVVAR_BOOLEANARRAY: // 21 - bool[]
type_name = "table(boolean)";
break;
case Tango::DEVVAR_STATEARRAY: // 31 - DevState[]
type_name = "table(DevState)";
break;
case Tango::DEVVAR_LONGSTRINGARRAY: // 17 - longstring[] ???
case Tango::DEVVAR_DOUBLESTRINGARRAY: // 18 - doublestring[] ???
case Tango::DEV_ENCODED: // 28 - DevEncoded
case Tango::DEV_ENUM: // 29 - DevEnum
case Tango::DEV_PIPE_BLOB: // 30 - DevPipeBlob
case Tango::DATA_TYPE_UNKNOWN: // 32 - unknown
default:
type_name = "-not-supported-";
break;
}
return type_name;
}

View File

@ -0,0 +1,31 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_AttrCmdInfo.h
//
// Bindings for AttributeInfoEx and CommandInfo classes
//
//-----------------------------------------------------------------------------
#ifndef __LUT_ATTRCMDINFO_H__
# define __LUT_ATTRCMDINFO_H__
#include <core/tango.h>
#include <core/lua.h>
#include <core/logging/log.h>
#include <core/lua/stack.h>
void lut_AttributeInfo(lua_State* L, Tango::AttributeInfoEx info);
void lut_CommandInfo(lua_State* L, Tango::CommandInfo info);
void lut_AttributeAlarmInfo(lua_State* L, Tango::AttributeAlarmInfo info);
void lut_ArchiveEventInfo(lua_State* L, Tango::ArchiveEventInfo info);
void lut_ChangeEventInfo(lua_State* L, Tango::ChangeEventInfo info);
void lut_PeriodicEventInfo(lua_State* L, Tango::PeriodicEventInfo info);
std::string to_lua_type_name(int type);
#endif /* __LUT_ATTRCMDINFO_H__ */

View File

@ -0,0 +1,148 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_AttributeProxy.cpp
//
// Binding for AttributeProxy class
//
//-----------------------------------------------------------------------------
#include "lut_AttributeProxy.h"
// WRAPPER CLASS --------------------------------------------------------------
AttributeProxyWrapper::AttributeProxyWrapper(const char* name)
{
attr = new Tango::AttributeProxy(name);
info = attr->get_config();
}
AttributeProxyWrapper::~AttributeProxyWrapper()
{
delete attr;
}
// TANGO API ------------------------------------------------------------------
int lut_AttributeProxy_state(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API AttributeProxy:state()");
AttributeProxyWrapper* udata = (AttributeProxyWrapper*)lut_getobj(L, 1);
std::string attr_name = udata->attr->name();
try
{
lut_DevState(L, udata->attr->state());
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, attr_name.c_str());
}
return 1;
}
int lut_AttributeProxy_status(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API AttributeProxy:status()");
AttributeProxyWrapper* udata = (AttributeProxyWrapper*)lut_getobj(L, 1);
std::string attr_name = udata->attr->name();
try
{
lua_pushstring(L, udata->attr->status().c_str());
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, attr_name.c_str());
}
return 1;
}
int lut_AttributeProxy_get_config(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API AttributeProxy:get_config()");
AttributeProxyWrapper* udata = (AttributeProxyWrapper*)lut_getobj(L, 1);
lut_AttributeInfo(L, udata->info);
return 1;
}
// LUA API --------------------------------------------------------------------
void lut_lua_register_AttributeProxy(lua_State* L)
{
// create table, register funcs and add it as AttributeProxy to lutango's table
lua_newtable(L);
va_lua_register(L, lut_AttributeProxy);
lua_setfield(L, -2, "AttributeProxy");
LUT_LOG(INFO, "Registered AttributeProxy table");
}
int lut_AttributeProxy_create(lua_State* L)
{
const char* name = luaL_checkstring(L, 1);
LUT_LOG(TRACE, "LUA API AttributeProxy:create(%s)", name);
// push userdata containing the DeviceProxy
AttributeProxyWrapper** udata = (AttributeProxyWrapper**)lua_newuserdata(L, sizeof(AttributeProxyWrapper*));
try
{
*udata = new AttributeProxyWrapper(name);
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, name);
}
// set metatable, that allows userdata proper garbage collection
luaL_newmetatable(L, LUT_ATTRIBUTEPROXY);
va_lua_register(L, lut_AttributeProxy_userdata);
lua_setmetatable(L, -2);
return 1;
}
int lut_AttributeProxy_destroy(lua_State* L)
{
LUT_LOG(TRACE, "LUA API AttributeProxy:destroy()");
AttributeProxyWrapper* udata = (AttributeProxyWrapper*)lut_getobj(L, 1);
delete udata;
return 0;
}
// aka read / write
int lut_AttributeProxy_call(lua_State* L)
{
AttributeProxyWrapper* udata = (AttributeProxyWrapper*)lut_getobj(L, 1);
std::string attr_name = udata->attr->name();
LUT_LOG(TRACE, "LUA API AttributeProxy(%s):call(...)", attr_name.c_str());
try
{
if(lua_isnoneornil(L, 2))
{
// called without arguments - read attribute
LUT_LOG(TRACE, "Reading attribute %s", attr_name.c_str());
lut_fromTangoType(L, udata->attr->read(), udata->info.data_type, udata->info.data_format);
return 1;
}
else
{
Tango::DeviceAttribute v = lut_toTangoType<Tango::DeviceAttribute>(L, 2, udata->info.data_type, udata->info.data_format);
v.set_name(attr_name);
udata->attr->write(v);
return 0;
}
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, attr_name.c_str());
}
return 0;
}

View File

@ -0,0 +1,78 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_AttributeProxy.h
//
// Binding for AttributeProxy class
//
//-----------------------------------------------------------------------------
#ifndef __LUT_ATTRIBUTEPROXY_H__
# define __LUT_ATTRIBUTEPROXY_H__
#include <string>
#include <vector>
#include <core/tango.h>
#include <core/lua.h>
#include <core/utils.h>
#include <core/lua/object.h>
#include <core/lua/stack.h>
#include <core/lua/version_agnostic.h>
#include <core/logging/log.h>
#include <core/tango/types.h>
#include <core/tango/AttrCmdInfo/lut_AttrCmdInfo.h>
#include <core/tango/DevState/lut_DevState.h>
#include <core/tango/DevFailed/lut_DevFailed.h>
#define LUT_ATTRIBUTEPROXY "lut_AttributeProxy"
// Wrapper class
class AttributeProxyWrapper
{
public:
Tango::AttributeProxy* attr;
Tango::AttributeInfoEx info;
AttributeProxyWrapper(const char* name);
~AttributeProxyWrapper();
};
// Tango API
int lut_AttributeProxy_state(lua_State* L);
int lut_AttributeProxy_status(lua_State* L);
int lut_AttributeProxy_get_config(lua_State* L);
// Lua API
void lut_lua_register_AttributeProxy(lua_State* L);
int lut_AttributeProxy_create(lua_State* L);
int lut_AttributeProxy_destroy(lua_State* L);
int lut_AttributeProxy_call(lua_State* L);
static const luaL_Reg lut_AttributeProxy[] =
{
// Lua API
{ "create", lut_AttributeProxy_create },
{ "call", lut_AttributeProxy_call },
// Tango API
{ "state", lut_AttributeProxy_state },
{ "status", lut_AttributeProxy_status },
{ "get_config", lut_AttributeProxy_get_config},
{ NULL, NULL }
};
static const luaL_Reg lut_AttributeProxy_userdata[] =
{
{ "__gc", lut_AttributeProxy_destroy },
{ NULL, NULL }
};
#endif /* __LUT_ATTRIBUTEPROXY_H__ */

View File

@ -0,0 +1,71 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_DevFailed.cpp
//
// Binding for DevFailed exceptions
//
//-----------------------------------------------------------------------------
#include "lut_DevFailed.h"
int lut_DevFailed(lua_State* L, Tango::DevFailed e, const char* source)
{
int nerr = e.errors.length();
lua_createtable(L, nerr, 2);
int top = lua_gettop(L);
lua_pushstring(L, source);
lua_setfield(L, -2, "source");
lua_pushboolean(L, true);
lua_setfield(L, -2, "is_DevFailed");
for(int i = 0; i < nerr; i++)
{
lua_pushnumber(L, i+1);
lua_createtable(L, 0, 4);
lua_pushstring(L, severity_str(e.errors[i].severity));
lua_setfield(L, -2, "severity");
lua_pushstring(L, e.errors[i].reason);
lua_setfield(L, -2, "reason");
lua_pushstring(L, e.errors[i].desc);
lua_setfield(L, -2, "desc");
lua_pushstring(L, e.errors[i].origin);
lua_setfield(L, -2, "origin");
lua_settable(L, top);
}
return lua_error(L);
}
const char* severity_str(Tango::ErrSeverity s)
{
switch(s)
{
case Tango::WARN:
return "WARNING";
break;
case Tango::ERR:
return "ERROR";
break;
case Tango::PANIC:
return "PANIC";
break;
default:
return "UNKNOWN";
break;
}
}

View File

@ -0,0 +1,23 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_DevFailed.h
//
// Binding for DevFailed exceptions
//
//-----------------------------------------------------------------------------
#ifndef __LUT_DEVFAILED_H__
# define __LUT_DEVFAILED_H__
#include <core/tango.h>
#include <core/lua.h>
int lut_DevFailed(lua_State* L, Tango::DevFailed e, const char* source);
const char* severity_str(Tango::ErrSeverity s);
#endif /* __LUT_DEVFAILED_H__ */

View File

@ -0,0 +1,27 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_DevState.cpp
//
// Binding for DevState type
//
//-----------------------------------------------------------------------------
#include "lut_DevState.h"
void lut_DevState(lua_State* L, Tango::DevState state)
{
LUT_LOG(TRACE, "Converting DevState(%d) into lut_DevState", state);
load_lua_lib(L, LUTANGO);
lua_getglobal(L, LUTANGO);
lua_getfield(L, -2, "DevState");
lua_pushnumber(L, (int)state);
lua_call(L, 1, 1);
}

View File

@ -0,0 +1,25 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_DevState.h
//
// Binding for DevState type
//
//-----------------------------------------------------------------------------
#ifndef __LUT_DEVSTATE_H__
# define __LUT_DEVSTATE_H__
#include <core/tango.h>
#include <core/lua.h>
#include <core/global.h>
#include <core/logging/log.h>
#include <core/lua/load.h>
void lut_DevState(lua_State* L, Tango::DevState state);
#endif /* __LUT_DEVSTATE_H__ */

View File

@ -0,0 +1,315 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_DeviceProxy.cpp
//
// Binding for DeviceProxy class
//
//-----------------------------------------------------------------------------
#include "lut_DeviceProxy.h"
// WRAPPER CLASS --------------------------------------------------------------
DeviceProxyWrapper::DeviceProxyWrapper(const char* name)
{
dev = new Tango::DeviceProxy(name);
Tango::AttributeInfoListEx* attrlist = dev->attribute_list_query_ex();
Tango::CommandInfoList* cmdlist = dev->command_list_query();
for(int i = 0; i < attrlist->size(); i++)
attr_info[(*attrlist)[i].name] = (*attrlist)[i];
for(int i = 0; i < cmdlist->size(); i++)
cmd_info[(*cmdlist)[i].cmd_name] = (*cmdlist)[i];
delete attrlist;
delete cmdlist;
}
DeviceProxyWrapper::~DeviceProxyWrapper()
{
delete dev;
}
// COMMAND WRAPPER ------------------------------------------------------------
int __cmd_wrapper(lua_State* L)
{
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lua_touserdata(L, lua_upvalueindex(1));
std::string dev_name = udata->dev->dev_name();
const char* cmd_name = lua_tostring(L, lua_upvalueindex(2));
std::string full_name = build_name(dev_name, cmd_name, true);
LUT_LOG(TRACE, "Running command wrapper %s", full_name.c_str());
int in_type = udata->cmd_info[cmd_name].in_type;
int out_type = udata->cmd_info[cmd_name].out_type;
LUT_LOG(TRACE, "Command: %s in:%d out:%d", full_name.c_str(), in_type, out_type);
try
{
Tango::DeviceData in = lut_toTangoType<Tango::DeviceData>(L, 1, in_type);
Tango::DeviceData out = udata->dev->command_inout(cmd_name, in);
lut_fromTangoType(L, out, out_type);
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, full_name.c_str());
}
return 1;
}
// TANGO API ------------------------------------------------------------------
int lut_DeviceProxy_status(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API DeviceProxy:status()");
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
std::string dev_name = udata->dev->dev_name();
try
{
lua_pushstring(L, udata->dev->status().c_str());
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, dev_name.c_str());
}
return 1;
}
int lut_DeviceProxy_get_attribute_list(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API DeviceProxy:get_attribute_list()");
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
std::string dev_name = udata->dev->dev_name();
try
{
std::vector<std::string>* attrlist = udata->dev->get_attribute_list();
lua_newtable(L);
for(int i = 0; i < attrlist->size(); i++)
{
lua_pushstring(L, (*attrlist)[i].c_str());
lua_rawseti(L, -2, i+1);
}
delete attrlist;
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, dev_name.c_str());
}
return 1;
}
int lut_DeviceProxy_get_attribute_config(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API DeviceProxy:get_attribute_config()");
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
const char* name = luaL_checkstring(L, 3); // arg[2] is Lua "self"
std::string dev_name = udata->dev->dev_name();
std::string full_name = build_name(dev_name, name);
if(udata->attr_info.find(name) == udata->attr_info.end())
{
LUT_LOG(ERROR, "Attribute %s not found!", full_name.c_str());
lua_pushnil(L);
}
else
lut_AttributeInfo(L, udata->attr_info[name]);
return 1;
}
int lut_DeviceProxy_attribute_list_query(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API DeviceProxy:attribute_list_query()");
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
lua_newtable(L);
int top = lua_gettop(L);
for(AttrInfoMap::iterator i = udata->attr_info.begin(); i != udata->attr_info.end(); i++)
{
lut_AttributeInfo(L, i->second);
lua_setfield(L, top, i->first.c_str());
}
return 1;
}
int lut_DeviceProxy_get_command_list(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API DeviceProxy:get_command_list()");
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
std::string dev_name = udata->dev->dev_name();
try
{
std::vector<std::string>* cmdlist = udata->dev->get_command_list();
lua_newtable(L);
for(int i = 0; i < cmdlist->size(); i++)
{
lua_pushstring(L, (*cmdlist)[i].c_str());
lua_rawseti(L, -2, i+1);
}
delete cmdlist;
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, dev_name.c_str());
}
return 1;
}
int lut_DeviceProxy_get_command_config(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API DeviceProxy:get_command_config()");
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
const char* name = luaL_checkstring(L, 3); // arg[2] is Lua "self"
std::string dev_name = udata->dev->dev_name();
std::string full_name = build_name(dev_name, name);
if(udata->cmd_info.find(name) == udata->cmd_info.end())
{
LUT_LOG(ERROR, "Command %s not found!", full_name.c_str());
lua_pushnil(L);
}
else
lut_CommandInfo(L, udata->cmd_info[name]);
return 1;
}
int lut_DeviceProxy_command_list_query(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API DeviceProxy:command_list_query()");
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
lua_newtable(L);
int top = lua_gettop(L);
for(CmdInfoMap::iterator i = udata->cmd_info.begin(); i != udata->cmd_info.end(); i++)
{
lut_CommandInfo(L, i->second);
lua_setfield(L, top, i->first.c_str());
}
return 1;
}
// LUA API --------------------------------------------------------------------
void lut_lua_register_DeviceProxy(lua_State* L)
{
// create table, register funcs and add it as DeviceProxy to lutango's table
lua_newtable(L);
va_lua_register(L, lut_DeviceProxy);
lua_setfield(L, -2, "DeviceProxy");
LUT_LOG(INFO, "Registered DeviceProxy table");
}
int lut_DeviceProxy_create(lua_State* L)
{
const char* name = luaL_checkstring(L, 1);
LUT_LOG(TRACE, "LUA API DeviceProxy:create(%s)", name);
// push userdata containing the DeviceProxy
DeviceProxyWrapper** udata = (DeviceProxyWrapper**)lua_newuserdata(L, sizeof(DeviceProxyWrapper*));
try
{
*udata = new DeviceProxyWrapper(name);
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, name);
}
// set metatable, that allows userdata proper garbage collection
luaL_newmetatable(L, LUT_DEVICEPROXY);
va_lua_register(L, lut_DeviceProxy_userdata);
lua_setmetatable(L, -2);
return 1;
}
int lut_DeviceProxy_destroy(lua_State* L)
{
LUT_LOG(TRACE, "LUA API DeviceProxy:destroy()");
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
delete udata;
return 0;
}
// aka read_attribute / run command
int lut_DeviceProxy_index(lua_State* L)
{
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
const char* name = luaL_checkstring(L, 2);
std::string dev_name = udata->dev->dev_name();
std::string full_name = build_name(dev_name, name);
LUT_LOG(TRACE, "LUA API DeviceProxy(%s):index(%s)", dev_name.c_str(), name);
if(udata->cmd_info.find(name) != udata->cmd_info.end())
{
// index is a command, push wrapper closure
// commands are supposed to be called, to allow this
// command "read" returns a function closure
lua_pushlightuserdata(L, udata);
lua_pushstring(L, name);
lua_pushcclosure(L, __cmd_wrapper, 2);
}
else if(udata->attr_info.find(name) != udata->attr_info.end())
{
// index is an attribute
try
{
LUT_LOG(TRACE, "Reading attribute %s", full_name.c_str());
Tango::DeviceAttribute attr = udata->dev->read_attribute(name);
lut_fromTangoType(L, attr, attr.get_type(), attr.get_data_format());
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, full_name.c_str());
}
}
else
{
LUT_LOG(ERROR, "%s is neither command nor attribute!", full_name.c_str());
lua_pushnil(L);
}
return 1;
}
// aka write_attribute
int lut_DeviceProxy_newindex(lua_State* L)
{
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
const char* attr_name = luaL_checkstring(L, 2);
std::string dev_name = udata->dev->dev_name();
std::string full_name = build_name(dev_name, attr_name);
LUT_LOG(TRACE, "LUA API DeviceProxy(%s):newindex(%s)", dev_name.c_str(), attr_name);
if(udata->attr_info.find(attr_name) == udata->attr_info.end())
LUT_LOG(ERROR, "Not an attribute: %s!", full_name.c_str());
else
{
try
{
Tango::DeviceAttribute v = lut_toTangoType<Tango::DeviceAttribute>(L, 3, udata->attr_info[attr_name].data_type, udata->attr_info[attr_name].data_format);
v.set_name(attr_name);
udata->dev->write_attribute(v);
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, full_name.c_str());
}
}
return 0;
}

View File

@ -0,0 +1,90 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: lut_DeviceProxy.h
//
// Binding for DeviceProxy class
//
//-----------------------------------------------------------------------------
#ifndef __LUT_DEVICEPROXY_H__
# define __LUT_DEVICEPROXY_H__
#include <string>
#include <vector>
#include <core/tango.h>
#include <core/lua.h>
#include <core/utils.h>
#include <core/lua/object.h>
#include <core/lua/version_agnostic.h>
#include <core/logging/log.h>
#include <core/tango/types.h>
#include <core/tango/AttrCmdInfo/lut_AttrCmdInfo.h>
#include <core/tango/DevFailed/lut_DevFailed.h>
#define LUT_DEVICEPROXY "lut_DeviceProxy"
// Wrapper class
class DeviceProxyWrapper
{
public:
Tango::DeviceProxy* dev;
AttrInfoMap attr_info;
CmdInfoMap cmd_info;
DeviceProxyWrapper(const char* name);
~DeviceProxyWrapper();
};
// Command wrapper
int __cmd_wrapper(lua_State* L);
// Tango API
int lut_DeviceProxy_status(lua_State* L);
int lut_DeviceProxy_get_attribute_list(lua_State* L);
int lut_DeviceProxy_get_attribute_config(lua_State* L);
int lut_DeviceProxy_attribute_list_query(lua_State* L);
int lut_DeviceProxy_get_command_list(lua_State* L);
int lut_DeviceProxy_get_command_config(lua_State* L);
int lut_DeviceProxy_command_list_query(lua_State* L);
// Lua API
void lut_lua_register_DeviceProxy(lua_State* L);
int lut_DeviceProxy_create(lua_State* L);
int lut_DeviceProxy_destroy(lua_State* L);
int lut_DeviceProxy_index(lua_State* L);
int lut_DeviceProxy_newindex(lua_State* L);
static const luaL_Reg lut_DeviceProxy[] =
{
// Lua API
{ "create", lut_DeviceProxy_create },
{ "index", lut_DeviceProxy_index },
{ "newindex", lut_DeviceProxy_newindex },
// Tango API
{ "status", lut_DeviceProxy_status },
{ "get_attribute_list", lut_DeviceProxy_get_attribute_list },
{ "get_attribute_config", lut_DeviceProxy_get_attribute_config },
{ "attribute_list_query", lut_DeviceProxy_attribute_list_query },
{ "get_command_list", lut_DeviceProxy_get_command_list },
{ "get_command_config", lut_DeviceProxy_get_command_config },
{ "command_list_query", lut_DeviceProxy_command_list_query },
{ NULL, NULL }
};
static const luaL_Reg lut_DeviceProxy_userdata[] =
{
{ "__gc", lut_DeviceProxy_destroy },
{ NULL, NULL }
};
#endif /* __LUT_DEVICEPROXY_H__ */

440
src/core/tango/types.cpp Normal file
View File

@ -0,0 +1,440 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: types.cpp
//
// Tango type conversions
//
//-----------------------------------------------------------------------------
#include "types.h"
template void lut_fromTangoType(lua_State* L, Tango::DeviceAttribute data, int type, Tango::AttrDataFormat format);
template void lut_fromTangoType(lua_State* L, Tango::DeviceData data, int type, Tango::AttrDataFormat format);
template<class T>
void lut_fromTangoType(lua_State* L, T data, int type, Tango::AttrDataFormat format)
{
switch(type)
{
case Tango::DEV_VOID: // 0 - void
lua_pushnil(L);
break;
case Tango::DEV_BOOLEAN: // 1 - bool
extract_bool(L, data, format);
break;
case Tango::DEV_SHORT: // 2 - short
extract_number<short>(L, data, format);
break;
case Tango::DEV_LONG: // 3 - long
extract_number<long>(L, data, format);
break;
case Tango::DEV_FLOAT: // 4 - float
extract_number<float>(L, data, format);
break;
case Tango::DEV_DOUBLE: // 5 - double
extract_number<double>(L, data, format);
break;
case Tango::DEV_USHORT: // 6 - ushort
extract_number<unsigned short>(L, data, format);
break;
case Tango::DEV_ULONG: // 7 - ulong
extract_number<unsigned long>(L, data, format);
break;
case Tango::DEV_STRING: // 8 - string
case Tango::DEVVAR_CHARARRAY: // 9 - char[]
case Tango::CONST_DEV_STRING: // 20 - const string
extract_string(L, data, format);
break;
case Tango::DEVVAR_SHORTARRAY: // 10 - short[]
{
std::vector<short> v;
data >> v;
push_number_table(L, v);
break;
}
case Tango::DEVVAR_LONGARRAY: // 11 - long[]
{
std::vector<long> v;
data >> v;
push_number_table(L, v);
break;
}
case Tango::DEVVAR_FLOATARRAY: // 12 - float[]
{
std::vector<float> v;
data >> v;
push_number_table(L, v);
break;
}
case Tango::DEVVAR_DOUBLEARRAY: // 13 - double[]
{
std::vector<double> v;
data >> v;
push_number_table(L, v);
break;
}
case Tango::DEVVAR_USHORTARRAY: // 14 - ushort[]
{
std::vector<unsigned short> v;
data >> v;
push_number_table(L, v);
break;
}
case Tango::DEVVAR_ULONGARRAY: // 15 - ulong[]
{
std::vector<unsigned long> v;
data >> v;
push_number_table(L, v);
break;
}
case Tango::DEVVAR_STRINGARRAY: // 16 - string[]
{
std::vector<std::string> v;
data >> v;
push_string_table(L, v);
break;
}
case Tango::DEV_STATE: // 19 - DevState
{
Tango::DevState v;
data >> v;
lut_DevState(L, v);
break;
}
case Tango::DEV_UCHAR: // 22 - uchar
{
unsigned char v;
// data >> v;
lua_pushstring(L, (const char *)&v);
break;
}
case Tango::DEV_LONG64: // 23 - long64
extract_number<int64_t>(L, data, format);
break;
case Tango::DEV_ULONG64: // 24 - ulong64
extract_number<uint64_t>(L, data, format);
break;
case Tango::DEVVAR_LONG64ARRAY: // 25 - long64[]
{
std::vector<int64_t> v;
data >> v;
push_number_table(L, v);
break;
}
case Tango::DEVVAR_ULONG64ARRAY: // 26 - ulong64[]
{
std::vector<uint64_t> v;
data >> v;
push_number_table(L, v);
break;
}
case Tango::DEV_INT: // 27 - int
extract_number<int>(L, data, format);
break;
case Tango::DEVVAR_LONGSTRINGARRAY: // 17 - longstring[] ???
case Tango::DEVVAR_DOUBLESTRINGARRAY: // 18 - doublestring[] ???
case Tango::DEVVAR_BOOLEANARRAY: // 21 - bool[]
case Tango::DEV_ENCODED: // 28 - DevEncoded
case Tango::DEV_ENUM: // 29 - DevEnum
case Tango::DEV_PIPE_BLOB: // 30 - DevPipeBlob
case Tango::DEVVAR_STATEARRAY: // 31 - DevState[]
LUT_LOG(WARNING, "Command type conversion not implemented yet: %d", type);
lua_pushnil(L);
break;
case Tango::DATA_TYPE_UNKNOWN: // 32 - unknown
default:
LUT_LOG(ERROR, "Unknown type: %d", type);
lua_pushnil(L);
break;
}
}
template Tango::DeviceAttribute lut_toTangoType(lua_State* L, int idx, int type, Tango::AttrDataFormat format);
template Tango::DeviceData lut_toTangoType(lua_State* L, int idx, int type, Tango::AttrDataFormat format);
template<class T>
T lut_toTangoType(lua_State* L, int idx, int type, Tango::AttrDataFormat format)
{
T data = T();
switch(type)
{
case Tango::DEV_VOID: // 0 - void
break;
case Tango::DEV_BOOLEAN: // 1 - bool
{
Tango::DevBoolean v = lua_toboolean(L, idx);
data << v;
break;
}
case Tango::DEV_SHORT: // 2 - short
{
Tango::DevShort v = luaL_checknumber(L, idx);
data << v;
break;
}
case Tango::DEV_LONG: // 3 - long
{
Tango::DevLong v = luaL_checknumber(L, idx);
data << v;
break;
}
case Tango::DEV_FLOAT: // 4 - float
{
Tango::DevFloat v = luaL_checknumber(L, idx);
data << v;
break;
}
case Tango::DEV_DOUBLE: // 5 - double
{
Tango::DevDouble v = luaL_checknumber(L, idx);
data << v;
break;
}
case Tango::DEV_USHORT: // 6 - ushort
{
Tango::DevUShort v = luaL_checknumber(L, idx);
data << v;
break;
}
case Tango::DEV_ULONG: // 7 - ulong
{
Tango::DevULong v = luaL_checknumber(L, idx);
data << v;
break;
}
case Tango::DEV_STRING: // 8 - string
case Tango::DEVVAR_CHARARRAY: // 9 - char[]
case Tango::CONST_DEV_STRING: // 20 - const string
{
const char* v = luaL_checkstring(L, idx);
data << v;
break;
}
case Tango::DEVVAR_SHORTARRAY: // 10 - short[]
{
std::vector<Tango::DevShort> v = pop_number_table<Tango::DevShort>(L, idx);
data << v;
break;
}
case Tango::DEVVAR_LONGARRAY: // 11 - long[]
{
std::vector<Tango::DevLong> v = pop_number_table<Tango::DevLong>(L, idx);
data << v;
break;
}
case Tango::DEVVAR_FLOATARRAY: // 12 - float[]
{
std::vector<Tango::DevFloat> v = pop_number_table<Tango::DevFloat>(L, idx);
data << v;
break;
}
case Tango::DEVVAR_DOUBLEARRAY: // 13 - double[]
{
std::vector<Tango::DevDouble> v = pop_number_table<Tango::DevDouble>(L, idx);
data << v;
break;
}
case Tango::DEVVAR_USHORTARRAY: // 14 - ushort[]
{
std::vector<Tango::DevUShort> v = pop_number_table<Tango::DevUShort>(L, idx);
data << v;
break;
}
case Tango::DEVVAR_ULONGARRAY: // 15 - ulong[]
{
std::vector<Tango::DevULong> v = pop_number_table<Tango::DevULong>(L, idx);
data << v;
break;
}
case Tango::DEVVAR_STRINGARRAY: // 16 - string[]
{
std::vector<std::string> v = pop_string_table(L, idx);
data << v;
break;
}
case Tango::DEV_LONG64: // 23 - long64
{
Tango::DevLong64 v = luaL_checknumber(L, idx);
data << v;
break;
}
case Tango::DEV_ULONG64: // 24 - ulong64
{
Tango::DevULong64 v = luaL_checknumber(L, idx);
data << v;
break;
}
case Tango::DEVVAR_LONG64ARRAY: // 25 - long64[]
{
std::vector<Tango::DevLong64> v = pop_number_table<Tango::DevLong64>(L, idx);
data << v;
break;
}
case Tango::DEVVAR_ULONG64ARRAY: // 26 - ulong64[]
{
std::vector<Tango::DevULong64> v = pop_number_table<Tango::DevULong64>(L, idx);
data << v;
break;
}
case Tango::DEV_INT: // 27 - int
{
int v = luaL_checknumber(L, idx);
data << v;
break;
}
case Tango::DEVVAR_LONGSTRINGARRAY: // 17 - longstring[] ???
case Tango::DEVVAR_DOUBLESTRINGARRAY: // 18 - doublestring[] ???
case Tango::DEV_STATE: // 19 - DevState
case Tango::DEVVAR_BOOLEANARRAY: // 21 - bool[]
case Tango::DEV_UCHAR: // 22 - uchar
case Tango::DEV_ENCODED: // 28 - DevEncoded
case Tango::DEV_ENUM: // 29 - DevEnum
case Tango::DEV_PIPE_BLOB: // 30 - DevPipeBlob
case Tango::DEVVAR_STATEARRAY: // 31 - DevState[]
LUT_LOG(WARNING, "Conversion to Tango type not implemented yet: %d", type);
break;
case Tango::DATA_TYPE_UNKNOWN: // 32 - unknown
default:
LUT_LOG(ERROR, "Tango type is unknown: %d", type);
break;
}
return data;
}
template<class dT, class T>
void extract_number(lua_State* L, T data, Tango::AttrDataFormat format)
{
if(format == Tango::SCALAR)
{
dT v;
data >> v;
lua_pushnumber(L, v);
}
else if(format == Tango::SPECTRUM)
{
std::vector<dT> v;
data >> v;
push_number_table(L, v);
}
else if(format == Tango::IMAGE)
{
// std::vector<std::vector<T>> v;
// //attr >> v;
// // push_number_2d(L, v);
LUT_LOG(WARNING, "IMAGE data format is not supported yet");
lua_pushnil(L);
}
else
{
LUT_LOG(ERROR, "Invalid data format");
lua_pushnil(L);
}
}
template<class T>
void extract_bool(lua_State* L, T data, Tango::AttrDataFormat format)
{
if(format == Tango::SCALAR)
{
bool v;
data >> v;
lua_pushboolean(L, v);
}
else if(format == Tango::SPECTRUM)
{
// TODO: cannot insert std::vector<bool(or DevBoolean)> to DeviceData
// std::vector<bool> v;
// data >> v;
// push_bool_table(L, v);
lua_pushnil(L);
}
else if(format == Tango::IMAGE)
{
LUT_LOG(WARNING, "IMAGE data format is not supported yet");
lua_pushnil(L);
}
else
{
LUT_LOG(ERROR, "Invalid data format");
lua_pushnil(L);
}
}
template<class T>
void extract_string(lua_State* L, T data, Tango::AttrDataFormat format)
{
if(format == Tango::SCALAR)
{
std::string v;
data >> v;
lua_pushstring(L, v.c_str());
}
else if(format == Tango::SPECTRUM)
{
std::vector<std::string> v;
data >> v;
push_string_table(L, v);
}
else if(format == Tango::IMAGE)
{
LUT_LOG(WARNING, "IMAGE data format is not supported yet");
lua_pushnil(L);
}
else
{
LUT_LOG(ERROR, "Invalid data format");
lua_pushnil(L);
}
}

46
src/core/tango/types.h Normal file
View File

@ -0,0 +1,46 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: types.h
//
// Tango type conversions
//
//-----------------------------------------------------------------------------
#ifndef __TYPES_H__
# define __TYPES_H__
#include <string>
#include <vector>
#include <map>
#include <inttypes.h>
#include <core/lua.h>
#include <core/tango.h>
#include <core/logging/log.h>
#include <core/lua/stack.h>
#include <core/tango/DevState/lut_DevState.h>
typedef std::map<std::string, Tango::AttributeInfoEx> AttrInfoMap;
typedef std::map<std::string, Tango::CommandInfo> CmdInfoMap;
template<class T>
void lut_fromTangoType(lua_State* L, T data, int type, Tango::AttrDataFormat format=Tango::SCALAR);
template<class T>
T lut_toTangoType(lua_State* L, int idx, int type, Tango::AttrDataFormat format=Tango::SCALAR);
template<class dT, class T>
void extract_number(lua_State* L, T data, Tango::AttrDataFormat format);
template<class T>
void extract_bool(lua_State* L, T data, Tango::AttrDataFormat format);
template<class T>
void extract_string(lua_State* L, T data, Tango::AttrDataFormat format);
#endif /* __TYPES_H__ */

23
src/core/utils.cpp Normal file
View File

@ -0,0 +1,23 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: utils.cpp
//
// Various utilities
//
//-----------------------------------------------------------------------------
#include "utils.h"
std::string build_name(std::string dev_name, std::string name, bool cmd)
{
std::string r(dev_name);
r += "/";
r += name;
if(cmd) r += "()";
return r;
}

21
src/core/utils.h Normal file
View File

@ -0,0 +1,21 @@
//-----------------------------------------------------------------------------
//
// luTango - Lua binding for Tango
//
// Copyright (C) 2023 Grzegorz Kowalski
// See LICENSE for legal information
//
// file: utils.h
//
// Various utilities
//
//-----------------------------------------------------------------------------
#ifndef __UTILS_H__
# define __UTILS_H__
#include <string>
std::string build_name(std::string dev_name, std::string name, bool cmd=false);
#endif /* __UTILS_H__ */

32
src/init.lua Normal file
View File

@ -0,0 +1,32 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: init.lua
--
-- Lua module entry point
--
-------------------------------------------------------------------------------
local log = require "lutango.log"
local core = require "lutango.core"
local utils = require "lutango.utils"
local lutObject = require "lutango.lutObject"
local lutango = {
__prefix = prefix,
log = log,
sys = core.sys,
lutObject = lutObject,
DeviceProxy = lutObject("DeviceProxy"),
AttributeProxy = lutObject("AttributeProxy"),
DevState = require "lutango.lutDevState"
}
lutango.sys.lua_version = utils.lua_version
log(log.level.TRACE, "luTango module ready")
return lutango

48
src/log.lua Normal file
View File

@ -0,0 +1,48 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: log.lua
--
-- Logging facilities for Lua part
--
-------------------------------------------------------------------------------
local core = require "lutango.core"
local utils = require "lutango.utils"
local _log_level = {
CRITICAL = 0,
ERROR = 1,
WARNING = 2,
INFO = 3,
DEBUG = 4,
TRACE = 5
}
local log = {
level = _log_level,
current_log_level = _log_level.WARNING
}
function log:__call(level, msg)
if level <= self.current_log_level then
level = utils.get_key_by_value(self.level, level)
local caller = debug.getinfo(2)
local file = utils.get_file_name(caller.source)
local func = caller.name or "<anonymous>"
local line = caller.linedefined
io.stderr:write("["..level.."]@[API:"..file..":"..func..":"..line.."]: "..msg.."\n")
end
end
function log:set_log_level(level)
self.current_log_level = level
core.log.set_log_level(level)
end
setmetatable(log, log)
return log

50
src/lutDevState.lua Normal file
View File

@ -0,0 +1,50 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: lutDevState.lua
--
-- DevState type implementation
--
-------------------------------------------------------------------------------
local utils = require "lutango.utils"
local log = require "lutango.log"
local lutDevState = {
labels = {[0] = "ON", "OFF", "CLOSE", "OPEN", "INSERT", "EXTRACT", "MOVING", "STANDBY", "FAULT", "INIT", "RUNNING", "ALARM", "DISABLE", "UNKNOWN"}
}
lutDevState.__index = lutDevState
function lutDevState:__call(state)
log(log.level.TRACE, "New DevState("..tostring(state)..")")
o = { value = state}
setmetatable(o, lutDevState)
return o
end
function lutDevState:number()
return self.value
end
function lutDevState:__tostring()
return self.labels[self.value]
end
function lutDevState:__eq(other)
return self.state == other.state
end
local r = {}
-- pregenerate available state objects
for i = 0,#lutDevState.labels do
r[lutDevState.labels[i]] = lutDevState:__call(i)
end
setmetatable(r, lutDevState)
return r

77
src/lutObject.lua Normal file
View File

@ -0,0 +1,77 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: lutObject.lua
--
-- Generic Lua object for interacting with C++ objects
--
-------------------------------------------------------------------------------
local core = require "lutango.core"
local log = require "lutango.log"
local try = require "lutango.try"
local lutObject = {}
local function create_lutObject(type)
log(log.level.TRACE, "New lutObject for "..type)
local o = {
__is_instance = false,
__type = type
}
setmetatable(o, lutObject)
return o
end
function lutObject:__call(...)
if self.__is_instance then
if self.__type then
return try(core[self.__type].call, self.__obj, ...)
else
return nil
end
else
log(log.level.TRACE, "New "..self.__type.."("..table.concat({...}, ", ")..")")
local o = {
__is_instance = true,
__type = self.__type
}
if self.__type then
o.__obj = try(core[self.__type].create, ...)
end
setmetatable(o, lutObject)
return o
end
end
function lutObject:__index(key)
if self.__type then
local from_core = core[self.__type][key]
if from_core then
return function(...)
return try(from_core, self.__obj, ...)
end
end
return try(core[self.__type].index, self.__obj, key)
else return nil end
end
function lutObject:__newindex(key, value)
if self.__type then
local from_core = core[self.__type][key]
if from_core then
log(log.level.ERROR, "Cannot write non-attribute: "..key)
return nil
end
try(core[self.__type].newindex, self.__obj, key, value)
else return nil end
end
return create_lutObject

39
src/try.lua Normal file
View File

@ -0,0 +1,39 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: try.lua
--
-- Exception handling
--
-------------------------------------------------------------------------------
require "lutango.version_agnostic"
local function default_handler(e)
io.stderr:write("\n=================================== EXCEPTION ===================================\n")
if e.is_DevFailed then
io.stderr:write("Tango Error Stack:\t"..e.source.."\n")
for i,v in ipairs(e) do
io.stderr:write("\t"..i..":\n")
io.stderr:write("\t\t"..v.severity.."\t\t"..v.reason.."\n")
io.stderr:write("\t\t"..v.desc.."\n")
io.stderr:write("\t\t"..v.origin.."\n\n")
end
else
io.stderr:write(tostring(e))
end
io.stderr:write(debug.traceback("", 6))
io.stderr:write("\n=================================================================================\n\n")
end
local function try(f, ...)
local f_arg = {...}
local ok, ret = xpcall(function() return f(va_unpack(f_arg)) end, default_handler)
return ret
end
return try

36
src/utils.lua Normal file
View File

@ -0,0 +1,36 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: utils.lua
--
-- Various utilities
--
-------------------------------------------------------------------------------
local utils = {}
function utils.get_key_by_value(t, value)
for k,v in pairs(t) do
if v == value then return k end
end
return nil
end
function utils.get_file_name(path)
return path:match("^.+[/\\](.+)$")
end
function utils.lua_version()
if type(jit) == "table" and jit.version then
-- running on LuaJIT
return jit.version.." (".._VERSION..")"
else
return _VERSION
end
end
return utils

21
src/version_agnostic.lua Normal file
View File

@ -0,0 +1,21 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: version_agnostic.lua
--
-- Facilitate different versions of Lua
-- WARNING! This module sets globals!
--
-------------------------------------------------------------------------------
local version = tonumber(_VERSION:match("%d.%d"))
if version > 5.1 then
va_unpack = table.unpack
else
va_unpack = unpack
end

27
tests/_print_kv.lua Normal file
View File

@ -0,0 +1,27 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: _print_kv.lua
--
-- Nested table printing utility
--
-------------------------------------------------------------------------------
local function print_kv(k, v, prefix)
prefix = prefix or ""
print(prefix..tostring(k)..": "..tostring(v))
if type(v) == "table" then
for kk,vv in ipairs(v) do
print_kv(kk, vv, prefix.."\t")
end
for kk,vv in pairs(v) do
print_kv(kk, vv, prefix.."\t")
end
end
end
return print_kv

38
tests/attributeproxy.lua Normal file
View File

@ -0,0 +1,38 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: attributeproxy.lua
--
-- Test script for AttributeProxy class
--
-------------------------------------------------------------------------------
local lut = require "lutango"
local print_kv = require "_print_kv"
lut.log:set_log_level(lut.log.level.WARNING)
local ap = lut.AttributeProxy("sys/tg_test/1/ampli")
print("Reading state and status")
print("State = "..tostring(ap:state()))
print("Status = "..ap:status())
print("Reading attribute")
local v = ap()
print("ampli = "..v)
print("Writing attribute")
ap(v+1)
print("Reading again")
print("ampli = "..ap())
local info = ap:get_config()
print("\nAttribute info: "..tostring(info))
for k,v in pairs(info) do
print_kv(k, v)
end

49
tests/dp_info.lua Normal file
View File

@ -0,0 +1,49 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: dp_info.lua
--
-- Test script for attribute and command info
--
-------------------------------------------------------------------------------
local lut = require "lutango"
local print_kv = require "_print_kv"
lut.log:set_log_level(lut.log.level.WARNING)
local dp = lut.DeviceProxy(arg[1] or "sys/tg_test/1")
print("Get full lists:")
local ai_list = dp:attribute_list_query()
for k,v in pairs(ai_list) do
print_kv(k, v)
end
local ci_list = dp:command_list_query()
for k,v in pairs(ci_list) do
print_kv(k, v)
end
print("\nGet single attr:")
local ai = dp:get_attribute_config("double_spectrum_ro")
for k,v in pairs(ai) do
print_kv(k, v)
end
print("\nGet single command:")
local ci = dp:get_command_config("DevLong64")
for k,v in pairs(ci) do
print_kv(k, v)
end
print("\nGet non-existent attr:")
local non_ai = dp:get_attribute_config("non_existent_attr")
print(tostring(non_ai))
print("\nGet non-existent command:")
local non_ci = dp:get_command_config("NonExistentCommand")
print(tostring(non_ci))

40
tests/invalid_actions.lua Normal file
View File

@ -0,0 +1,40 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: invalid_actions.lua
--
-- Test script attempting to perform various invalid actions
--
-------------------------------------------------------------------------------
local lut = require "lutango"
lut.log:set_log_level(lut.log.level.TRACE)
print("Attempting to access non-existent device")
local invalid = lut.DeviceProxy("non/existent/device")
local dp = lut.DeviceProxy(arg[1] or "sys/tg_test/1")
print("Attempting to write core function")
dp.get_attribute_list = 120
print("Attempting to write device command")
dp.SwitchStates = 0
print("Attempting to write read-only attribute")
dp.short_scalar_ro = 100
print("Attempting to access non-existent attribute")
local invalid2 = lut.AttributeProxy("sys/tg_test/1/nonexistent")
print("Attempting to write read-only attribute via AttributeProxy")
local attr_name = "sys/tg_test/1/short_scalar_ro"
if arg[1] and arg[2] then
attr_name = arg[1].."/"..arg[2]
end
local ap = lut.AttributeProxy(attr_name)
ap(100)

19
tests/print_versions.lua Normal file
View File

@ -0,0 +1,19 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: print_versions.lua
--
-- Test script printing libraries, interpreter and compiler versions
--
-------------------------------------------------------------------------------
local lut = require "lutango"
print("luTango "..lut.sys.version())
print("Tango "..lut.sys.tango_version())
print(lut.sys.cpp_version())
print(lut.sys.lua_version())

36
tests/read_attrs.lua Normal file
View File

@ -0,0 +1,36 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: read_attrs.lua
--
-- Test script for reading attributes
--
-------------------------------------------------------------------------------
local lut = require "lutango"
lut.log:set_log_level(lut.log.level.WARNING)
local dp = lut.DeviceProxy(arg[1] or "sys/tg_test/1")
local attrlist = dp:get_attribute_list()
for _,v in ipairs(attrlist) do
local r = dp[v]
io.write(v.." = "..tostring(r))
if type(r) == "table" then
io.write(": {")
for _,i in ipairs(r) do
io.write(tostring(i)..", ")
end
io.write("}")
end
print()
end
print("\nReading non existent attribute")
local ne = dp.non_existent_attr
print(tostring(ne))

80
tests/run_cmds.lua Normal file
View File

@ -0,0 +1,80 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: run_cmds.lua
--
-- Test script for running commands
--
-------------------------------------------------------------------------------
local lut = require "lutango"
lut.log:set_log_level(lut.log.level.WARNING)
local dp = lut.DeviceProxy(arg[1] or "sys/tg_test/1")
function run_void_cmd(cmd)
io.write(cmd.."(): ")
print(dp[cmd]())
end
function run_scalar_cmd(cmd, input)
io.write(cmd.."("..tostring(input).."): ")
print(dp[cmd](input))
end
function run_array_cmd(cmd, input)
io.write(cmd.."({")
for _,v in ipairs(input) do
io.write(v..", ")
end
io.write("}): ")
local r = dp[cmd](input)
io.write(tostring(r)..": {")
for _,v in ipairs(input) do
io.write(v..", ")
end
print("}")
end
run_void_cmd("State")
run_void_cmd("Status")
run_void_cmd("SwitchStates")
run_void_cmd("DevVoid")
run_scalar_cmd("DevBoolean", true)
run_scalar_cmd("DevBoolean", false)
run_scalar_cmd("DevDouble", 88.888)
run_scalar_cmd("DevDouble", -88.888)
run_scalar_cmd("DevFloat", 8.88)
run_scalar_cmd("DevFloat", -8.88)
run_scalar_cmd("DevLong", 99112233)
run_scalar_cmd("DevLong", -99112233)
run_scalar_cmd("DevLong64", 1199228833775566)
run_scalar_cmd("DevLong64", -1199228833775566)
run_scalar_cmd("DevShort", 101)
run_scalar_cmd("DevShort", -101)
run_scalar_cmd("DevString", "hello world")
run_scalar_cmd("DevULong", 9911223344)
run_scalar_cmd("DevULong64", 1199228833775566)
run_scalar_cmd("DevUShort", 101)
-- run_scalar_cmd("DevVarCharArray", "hello world")
run_array_cmd("DevVarDoubleArray", {1.1111, -2.2222, 3.3333})
-- run_array_cmd("DevVarDoubleStringArray", {???})
run_array_cmd("DevVarFloatArray", {1.11, -2.22, 3.33})
run_array_cmd("DevVarLong64Array", {11111111111, -22222222222, 33333333333})
run_array_cmd("DevVarLongArray", {11111111111, -22222222222, 33333333333})
-- run_array_cmd("DevVarLongStringArray", {???})
run_array_cmd("DevVarShortArray", {1111, -2222, 3333})
run_array_cmd("DevVarStringArray", {"hello", "world", "from", "Lua"})
run_array_cmd("DevVarULong64Array", {11111111111, 22222222222, 33333333333})
run_array_cmd("DevVarULongArray", {11111111111, 22222222222, 33333333333})
run_array_cmd("DevVarUShortArray", {1111, 2222, 3333})
print("\nRunning non-existent command:")
local ok, ret = pcall(dp.NonExistentCmd)
print("ok="..tostring(ok).." ret="..tostring(ret))

35
tests/test_state.lua Normal file
View File

@ -0,0 +1,35 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: test_state.lua
--
-- Test script for DevState class
--
-------------------------------------------------------------------------------
local lut = require "lutango"
local states = {}
for i = 0,13 do
states[i] = lut.DevState(i)
print(tostring(states[i]).." = "..states[i]:number())
end
print(states[0] == lut.DevState.ON)
print(states[1] == lut.DevState.OFF)
print(states[2] == lut.DevState.CLOSE)
print(states[3] == lut.DevState.OPEN)
print(states[4] == lut.DevState.INSERT)
print(states[5] == lut.DevState.EXTRACT)
print(states[6] == lut.DevState.MOVING)
print(states[7] == lut.DevState.STANDBY)
print(states[8] == lut.DevState.FAULT)
print(states[9] == lut.DevState.INIT)
print(states[10] == lut.DevState.RUNNING)
print(states[11] == lut.DevState.ALARM)
print(states[12] == lut.DevState.DISABLE)
print(states[13] == lut.DevState.UNKNOWN)

21
tests/write_attrs.lua Normal file
View File

@ -0,0 +1,21 @@
-------------------------------------------------------------------------------
--
-- luTango - Lua binding for Tango
--
-- Copyright (C) 2023 Grzegorz Kowalski
-- See LICENSE for legal information
--
-- file: write_attrs.lua
--
-- Test script for writing attributes
--
-------------------------------------------------------------------------------
local lut = require "lutango"
lut.log:set_log_level(lut.log.level.WARNING)
dp = lut.DeviceProxy(arg[1] or "sys/tg_test/1")
dp.ampli = dp.ampli + 1
local b = dp.boolean_scalar
dp.boolean_scalar = not b