add command support, refactor attr data handling

This commit is contained in:
Grzegorz Kowalski 2023-02-03 22:00:26 +01:00
parent 22ef574220
commit 7e942585af
9 changed files with 494 additions and 94 deletions

View File

@ -22,7 +22,7 @@ SOLINK := core.so
CC = g++
CXX = $(CC)
CFLAGS = -shared -fpic -D_REENTRANT -DVERSION=\"$(VERSION)\" -I$(LUT_INCLUDE)
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)

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

@ -0,0 +1,21 @@
#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);
}
}

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

@ -0,0 +1,32 @@
#ifndef __STACK_H__
# define __STACK_H__
#include <string>
#include <vector>
#include <core/lua.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);
// 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>
T pop_number(lua_State* L, int idx)
{
LUT_LOG(TRACE, "Popping number value from stack");
return (T)luaL_checknumber(L, idx);
}
#endif /* __STACK_H__ */

View File

@ -11,6 +11,29 @@ DeviceProxyWrapper::~DeviceProxyWrapper()
delete dev;
}
// COMMAND WRAPPER ------------------------------------------------------------
int cmd_wrapper(lua_State* L)
{
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lua_touserdata(L, lua_upvalueindex(1));
const char* name = lua_tostring(L, lua_upvalueindex(2));
LUT_LOG(TRACE, "Running command wrapper %s/%s()", udata->dev->name().c_str(), name);
if(udata->cmd_info.find(name) == udata->cmd_info.end())
{
LUT_LOG(TRACE, "Command info for %s doesn't exist, fetching first", name);
udata->cmd_info[name] = udata->dev->get_command_config(name);
}
long in_type = udata->cmd_info[name].in_type;
long out_type = udata->cmd_info[name].out_type;
LUT_LOG(TRACE, "Command: %s in:%d out:%d", name, in_type, out_type);
Tango::DeviceData in = pack_cmd_data(L, 2, in_type);
Tango::DeviceData out = udata->dev->command_inout(name, in);
unpack_cmd_data(L, out, out_type);
return 1;
}
// TANGO API ------------------------------------------------------------------
int lut_DeviceProxy_status(lua_State* L)
{
@ -24,13 +47,29 @@ 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);
vector<string>* attrlist = udata->dev->get_attribute_list();
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;
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::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;
return 1;
}
@ -71,21 +110,34 @@ int lut_DeviceProxy_destroy(lua_State* L)
return 0;
}
// aka read_attribute
// aka read_attribute / run command
int lut_DeviceProxy_index(lua_State* L)
{
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
const char* attr_name = luaL_checkstring(L, 2);
const char* name = luaL_checkstring(L, 2);
LUT_LOG(TRACE, "LUA API DeviceProxy:index(%s)", attr_name);
Tango::DeviceAttribute attr = udata->dev->read_attribute(attr_name);
udata->type_map[attr_name].type = attr.get_type();
udata->type_map[attr_name].format = attr.get_data_format();
extract_and_push(L, attr);
LUT_LOG(TRACE, "LUA API DeviceProxy:index(%s)", name);
std::vector<std::string>* cmdlist = udata->dev->get_command_list();
if(std::count(cmdlist->begin(), cmdlist->end(), name))
{
// 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
{
// index is an attribute
LUT_LOG(TRACE, "Reading attribute %s", name);
Tango::DeviceAttribute attr = udata->dev->read_attribute(name);
udata->type_map[name].type = attr.get_type();
udata->type_map[name].format = attr.get_data_format();
unpack_attr_data(L, attr);
}
delete cmdlist;
return 1;
}
@ -97,16 +149,25 @@ int lut_DeviceProxy_newindex(lua_State* L)
LUT_LOG(TRACE, "LUA API DeviceProxy:newindex(%s)", attr_name);
std::vector<std::string>* attrlist = udata->dev->get_attribute_list();
if(!std::count(attrlist->begin(), attrlist->end(), attr_name))
{
// name is not an attribute
LUT_LOG(ERROR, "Not an attribute: %s", attr_name);
return 0;
}
if(udata->type_map.find(attr_name) == udata->type_map.end())
{
// no cached type mapping
LUT_LOG(TRACE, "Type mapping for attribute %s doesn't exist, reading first", attr_name);
Tango::DeviceAttribute attr = udata->dev->read_attribute(attr_name);
udata->type_map[attr_name].type = attr.get_type();
udata->type_map[attr_name].format = attr.get_data_format();
}
Tango::DeviceAttribute v = pop_and_pack(L, udata->type_map[attr_name], attr_name);
Tango::DeviceAttribute v = pack_attr_data(L, udata->type_map[attr_name], attr_name);
udata->dev->write_attribute(v);
return 1;
return 0;
}

View File

@ -1,6 +1,9 @@
#ifndef __LUT_DEVICEPROXY_H__
# define __LUT_DEVICEPROXY_H__
#include <string>
#include <vector>
#include <core/tango.h>
#include <core/lua.h>
@ -8,6 +11,7 @@
#include <core/logging/log.h>
#include <core/tango/attrdata.h>
#include <core/tango/cmddata.h>
#define LUT_DEVICEPROXY "lut_DeviceProxy"
@ -19,11 +23,17 @@ class DeviceProxyWrapper
~DeviceProxyWrapper();
Tango::DeviceProxy* dev;
AttrTypeMap type_map;
CmdInfoMap cmd_info;
};
// 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_command_list(lua_State* L);
int lut_DeviceProxy_command_wrapper(lua_State* L);
// Lua API
void lut_lua_register_DeviceProxy(lua_State* L);
@ -41,7 +51,8 @@ static const luaL_reg lut_DeviceProxy[] =
// Tango API
{ "status", lut_DeviceProxy_status },
{ "get_attribute_list", lut_DeviceProxy_get_attribute_list},
{ "get_attribute_list", lut_DeviceProxy_get_attribute_list },
{ "get_command_list", lut_DeviceProxy_get_command_list },
{ NULL, NULL }
};

View File

@ -1,6 +1,6 @@
#include "attrdata.h"
void extract_and_push(lua_State* L, Tango::DeviceAttribute attr)
void unpack_attr_data(lua_State* L, Tango::DeviceAttribute attr)
{
switch(attr.get_type())
{
@ -9,37 +9,37 @@ void extract_and_push(lua_State* L, Tango::DeviceAttribute attr)
break;
case 1: // bool
push_bool(L, attr);
push_attr_bool(L, attr);
break;
case 2: // short
push_number<short>(L, attr);
push_attr_number<short>(L, attr);
break;
case 3: // long
push_number<long>(L, attr);
push_attr_number<long>(L, attr);
break;
case 4: // float
push_number<float>(L, attr);
push_attr_number<float>(L, attr);
break;
case 5: // double
push_number<double>(L, attr);
push_attr_number<double>(L, attr);
break;
case 6: // ushort
push_number<unsigned short>(L, attr);
push_attr_number<unsigned short>(L, attr);
break;
case 7: // ulong
push_number<unsigned long>(L, attr);
push_attr_number<unsigned long>(L, attr);
break;
case 8: // string
case 9: // char[]
case 20: // const string
push_string(L, attr);
push_attr_string(L, attr);
break;
case 10: // short[]
@ -115,11 +115,11 @@ void extract_and_push(lua_State* L, Tango::DeviceAttribute attr)
}
case 23: // long64
push_number<int64_t>(L, attr);
push_attr_number<int64_t>(L, attr);
break;
case 24: // ulong64
push_number<uint64_t>(L, attr);
push_attr_number<uint64_t>(L, attr);
break;
case 25: // long64[]
@ -139,7 +139,7 @@ void extract_and_push(lua_State* L, Tango::DeviceAttribute attr)
}
case 27: // int
push_number<int>(L, attr);
push_attr_number<int>(L, attr);
break;
case 17: // longstring[] ???
@ -158,7 +158,7 @@ void extract_and_push(lua_State* L, Tango::DeviceAttribute attr)
}
template<class T>
void push_number(lua_State* L, Tango::DeviceAttribute attr)
void push_attr_number(lua_State* L, Tango::DeviceAttribute attr)
{
Tango::AttrDataFormat fmt = attr.get_data_format();
if(fmt == Tango::SCALAR)
@ -188,7 +188,7 @@ void push_number(lua_State* L, Tango::DeviceAttribute attr)
}
}
void push_bool(lua_State* L, Tango::DeviceAttribute attr)
void push_attr_bool(lua_State* L, Tango::DeviceAttribute attr)
{
Tango::AttrDataFormat fmt = attr.get_data_format();
if(fmt == Tango::SCALAR)
@ -216,7 +216,7 @@ void push_bool(lua_State* L, Tango::DeviceAttribute attr)
}
void push_string(lua_State* L, Tango::DeviceAttribute attr)
void push_attr_string(lua_State* L, Tango::DeviceAttribute attr)
{
Tango::AttrDataFormat fmt = attr.get_data_format();
if(fmt == Tango::SCALAR)
@ -243,38 +243,7 @@ void push_string(lua_State* L, Tango::DeviceAttribute attr)
}
}
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);
}
}
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);
}
}
Tango::DeviceAttribute pop_and_pack(lua_State* L, AttrTypeDescription d, const char* attr_name)
Tango::DeviceAttribute pack_attr_data(lua_State* L, AttrTypeDescription d, const char* attr_name)
{
switch(d.type)
{
@ -284,49 +253,49 @@ Tango::DeviceAttribute pop_and_pack(lua_State* L, AttrTypeDescription d, const c
case 1: // bool
// Lua 5.1 is missing the luaL_checkboolean function
return pack_value(attr_name, (bool)lua_toboolean(L, 3));
return pack_attr_value(attr_name, (bool)lua_toboolean(L, 3));
break;
case 2: // short
return pack_value(attr_name, pop_number<short>(L, 3));
return pack_attr_value(attr_name, pop_number<short>(L, 3));
break;
case 3: // long
return pack_value(attr_name, pop_number<long>(L, 3));
return pack_attr_value(attr_name, pop_number<long>(L, 3));
break;
case 4: // float
return pack_value(attr_name, pop_number<float>(L, 3));
return pack_attr_value(attr_name, pop_number<float>(L, 3));
break;
case 5: // double
return pack_value(attr_name, pop_number<double>(L, 3));
return pack_attr_value(attr_name, pop_number<double>(L, 3));
break;
case 6: // ushort
return pack_value(attr_name, pop_number<unsigned short>(L, 3));
return pack_attr_value(attr_name, pop_number<unsigned short>(L, 3));
break;
case 7: // ulong
return pack_value(attr_name, pop_number<unsigned long>(L, 3));
return pack_attr_value(attr_name, pop_number<unsigned long>(L, 3));
break;
case 8: // string
case 9: // char[]
case 20: // const string
return pack_value(attr_name, luaL_checkstring(L, 3));
return pack_attr_value(attr_name, luaL_checkstring(L, 3));
break;
case 23: // long64
return pack_value(attr_name, pop_number<int64_t>(L, 3));
return pack_attr_value(attr_name, pop_number<int64_t>(L, 3));
break;
case 24: // ulong64
return pack_value(attr_name, pop_number<uint64_t>(L, 3));
return pack_attr_value(attr_name, pop_number<uint64_t>(L, 3));
break;
case 27: // int
return pack_value(attr_name, pop_number<int>(L, 3));
return pack_attr_value(attr_name, pop_number<int>(L, 3));
break;
case 10: // short[]
@ -353,13 +322,7 @@ Tango::DeviceAttribute pop_and_pack(lua_State* L, AttrTypeDescription d, const c
}
template<class T>
T pop_number(lua_State* L, int idx)
{
return luaL_checknumber(L, idx);
}
template<class T>
Tango::DeviceAttribute pack_value(const char* name, T value)
Tango::DeviceAttribute pack_attr_value(const char* name, T value)
{
Tango::DeviceAttribute v(name, value);
return v;

View File

@ -1,6 +1,7 @@
#ifndef __ATTRDATA_H__
# define __ATTRDATA_H__
#include <string>
#include <vector>
#include <map>
#include <inttypes.h>
@ -8,6 +9,7 @@
#include <core/lua.h>
#include <core/tango.h>
#include <core/logging/log.h>
#include <core/lua/stack.h>
typedef struct
{
@ -18,25 +20,17 @@ typedef struct
typedef std::map<const char*, AttrTypeDescription> AttrTypeMap;
// READ ATTRIBUTE -------------------------------------------------------------
void extract_and_push(lua_State* L, Tango::DeviceAttribute attr);
void unpack_attr_data(lua_State* L, Tango::DeviceAttribute attr);
template<class T>
void push_number(lua_State* L, Tango::DeviceAttribute attr);
void push_bool(lua_State* L, Tango::DeviceAttribute attr);
void push_string(lua_State* L, Tango::DeviceAttribute attr);
template<class T>
void push_number_table(lua_State* L, std::vector<T> value);
void push_bool_table(lua_State* L, std::vector<bool> value);
void push_string_table(lua_State* L, std::vector<std::string> value);
void push_attr_number(lua_State* L, Tango::DeviceAttribute attr);
void push_attr_bool(lua_State* L, Tango::DeviceAttribute attr);
void push_attr_string(lua_State* L, Tango::DeviceAttribute attr);
// WRITE ATTRIBUTE ------------------------------------------------------------
Tango::DeviceAttribute pop_and_pack(lua_State* L, AttrTypeDescription d, const char* attr_name);
Tango::DeviceAttribute pack_attr_data(lua_State* L, AttrTypeDescription d, const char* attr_name);
template<class T>
T pop_number(lua_State* L, int idx);
template<class T>
Tango::DeviceAttribute pack_value(const char* name, T value);
Tango::DeviceAttribute pack_attr_value(const char* name, T value);
#endif /* __ATTRDATA_H__ */

292
src/core/tango/cmddata.cpp Normal file
View File

@ -0,0 +1,292 @@
#include "cmddata.h"
void unpack_cmd_data(lua_State* L, Tango::DeviceData data, long type)
{
switch(type)
{
case 0: // void
lua_pushnil(L);
break;
case 1: // bool
push_cmd_bool(L, data);
break;
case 2: // short
push_cmd_number<short>(L, data);
break;
case 3: // long
push_cmd_number<long>(L, data);
break;
case 4: // float
push_cmd_number<float>(L, data);
break;
case 5: // double
push_cmd_number<double>(L, data);
break;
case 6: // ushort
push_cmd_number<unsigned short>(L, data);
break;
case 7: // ulong
push_cmd_number<unsigned long>(L, data);
break;
case 8: // string
case 9: // char[]
case 20: // const string
push_cmd_string(L, data);
break;
case 10: // short[]
{
std::vector<short> v;
data >> v;
push_number_table(L, v);
break;
}
case 11: // long[]
{
std::vector<long> v;
data >> v;
push_number_table(L, v);
break;
}
case 12: // float[]
{
std::vector<float> v;
data >> v;
push_number_table(L, v);
break;
}
case 13: // double[]
{
std::vector<double> v;
data >> v;
push_number_table(L, v);
break;
}
case 14: // ushort[]
{
std::vector<unsigned short> v;
data >> v;
push_number_table(L, v);
break;
}
case 15: // ulong[]
{
std::vector<unsigned long> v;
data >> v;
push_number_table(L, v);
break;
}
case 16: // string[]
{
std::vector<std::string> v;
data >> v;
push_string_table(L, v);
break;
}
case 21: // bool[]
{
std::vector<bool> v;
//data >> v;
push_bool_table(L, v);
break;
}
case 22: // uchar
{
unsigned char v;
// data >> v;
lua_pushstring(L, (const char *)&v);
break;
}
case 23: // long64
push_cmd_number<int64_t>(L, data);
break;
case 24: // ulong64
push_cmd_number<uint64_t>(L, data);
break;
case 25: // long64[]
{
std::vector<int64_t> v;
data >> v;
push_number_table(L, v);
break;
}
case 26: // ulong64[]
{
std::vector<uint64_t> v;
data >> v;
push_number_table(L, v);
break;
}
case 27: // int
push_cmd_number<int>(L, data);
break;
case 17: // longstring[] ???
case 18: // doublestring[] ???
case 19: // DevState
case 28: // DevEncoded
LUT_LOG(WARNING, "Command type conversion not implemented yet: %d", type);
lua_pushnil(L);
break;
default:
LUT_LOG(ERROR, "Unknown type: %d", type);
lua_pushnil(L);
//return luaL_error(L, "Device returned type %d, that is unknown or unsupported.", attr.get_type());
}
}
template<class T>
void push_cmd_number(lua_State* L, Tango::DeviceData data)
{
T v;
data >> v;
lua_pushnumber(L, v);
}
void push_cmd_bool(lua_State* L, Tango::DeviceData data)
{
bool v;
data >> v;
lua_pushboolean(L, v);
}
void push_cmd_string(lua_State* L, Tango::DeviceData data)
{
std::string v;
data >> v;
lua_pushstring(L, v.c_str());
}
Tango::DeviceData pack_cmd_data(lua_State* L, int idx, long type)
{
Tango::DeviceData data;
switch(type)
{
case 0: // void
break;
case 1: // bool
{
bool v = lua_toboolean(L, idx);
data << v;
break;
}
case 2: // short
{
short v = pop_number<short>(L, idx);
data << v;
break;
}
case 3: // long
{
long v = pop_number<long>(L, idx);
data << v;
break;
}
case 4: // float
{
float v = pop_number<float>(L, idx);
data << v;
break;
}
case 5: // double
{
double v = pop_number<double>(L, idx);
data << v;
break;
}
case 6: // ushort
{
unsigned short v = pop_number<unsigned short>(L, idx);
data << v;
break;
}
case 7: // ulong
{
unsigned long v = pop_number<unsigned long>(L, idx);
data << v;
break;
}
case 8: // string
case 9: // char[]
case 20: // const string
{
const char* v = luaL_checkstring(L, idx);
data << v;
break;
}
case 23: // long64
{
// int64_t v = pop_number<int64_t>(L, idx);
// data << v;
break;
}
case 24: // ulong64
{
// uint64_t v = pop_number<uint64_t>(L, idx);
// data << v;
break;
}
case 27: // int
{
int v = pop_number<int>(L, idx);
data << v;
break;
}
case 10: // short[]
case 11: // long[]
case 12: // float[]
case 13: // double[]
case 14: // ushort[]
case 15: // ulong[]
case 16: // string[]
case 17: // longstring[] ???
case 18: // doublestring[] ???
case 19: // DevState
case 21: // bool[]
case 22: // uchar
case 25: // long64[]
case 26: // ulong64[]
case 28: // DevEncoded
LUT_LOG(WARNING, "Command input argument type not implemented yet: %d", type);
break;
default:
LUT_LOG(ERROR, "Command input argument type is unknown: %d", type);
}
return data;
}

26
src/core/tango/cmddata.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef __CMDDATA_H__
# define __CMDDATA_H__
#include <string>
#include <vector>
#include <inttypes.h>
#include <core/lua.h>
#include <core/tango.h>
#include <core/logging/log.h>
#include <core/lua/stack.h>
typedef std::map<const char*, Tango::CommandInfo> CmdInfoMap;
// DATA OUT -------------------------------------------------------------------
void unpack_cmd_data(lua_State* L, Tango::DeviceData data, long type);
// DATA IN --------------------------------------------------------------------
template<class T>
void push_cmd_number(lua_State* L, Tango::DeviceData data);
void push_cmd_bool(lua_State* L, Tango::DeviceData data);
void push_cmd_string(lua_State* L, Tango::DeviceData data);
Tango::DeviceData pack_cmd_data(lua_State* L, int idx, long type);
#endif /* __CMDDATA_H__ */