add error handling

This commit is contained in:
Grzegorz Kowalski 2023-02-05 01:34:46 +01:00
parent a93c8292f1
commit 69143b963b
10 changed files with 252 additions and 76 deletions

View File

@ -0,0 +1,55 @@
#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, 1);
int top = lua_gettop(L);
lua_pushstring(L, source);
lua_setfield(L, -2, "source");
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,10 @@
#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

@ -15,22 +15,32 @@ DeviceProxyWrapper::~DeviceProxyWrapper()
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);
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);
if(udata->cmd_info.find(name) == udata->cmd_info.end())
LUT_LOG(TRACE, "Running command wrapper %s", full_name.c_str());
try
{
LUT_LOG(TRACE, "Command info for %s doesn't exist, fetching first", name);
udata->cmd_info[name] = udata->dev->get_command_config(name);
if(udata->cmd_info.find(cmd_name) == udata->cmd_info.end())
{
LUT_LOG(TRACE, "Command info for %s doesn't exist, fetching first", full_name.c_str());
udata->cmd_info[cmd_name] = udata->dev->get_command_config(cmd_name);
}
long in_type = udata->cmd_info[cmd_name].in_type;
long 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);
Tango::DeviceData in = pack_cmd_data(L, 1, in_type);
Tango::DeviceData out = udata->dev->command_inout(cmd_name, in);
unpack_cmd_data(L, out, out_type);
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, full_name.c_str());
}
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, 1, in_type);
Tango::DeviceData out = udata->dev->command_inout(name, in);
unpack_cmd_data(L, out, out_type);
return 1;
}
@ -39,7 +49,17 @@ int lut_DeviceProxy_status(lua_State* L)
{
LUT_LOG(TRACE, "TANGO API DeviceProxy:status()");
DeviceProxyWrapper* udata = (DeviceProxyWrapper*)lut_getobj(L, 1);
lua_pushstring(L, udata->dev->status().c_str());
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;
}
@ -47,14 +67,23 @@ 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::vector<std::string>* attrlist = udata->dev->get_attribute_list();
lua_newtable(L);
for(int i = 0; i < attrlist->size(); i++)
std::string dev_name = udata->dev->dev_name();
try
{
lua_pushstring(L, (*attrlist)[i].c_str());
lua_rawseti(L, -2, i+1);
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());
}
delete attrlist;
return 1;
}
@ -62,14 +91,24 @@ 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++)
std::string dev_name = udata->dev->dev_name();
try
{
lua_pushstring(L, (*cmdlist)[i].c_str());
lua_rawseti(L, -2, i+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;
}
catch(Tango::DevFailed e)
{
lut_DevFailed(L, e, dev_name.c_str());
}
delete cmdlist;
return 1;
}
@ -92,7 +131,14 @@ int lut_DeviceProxy_create(lua_State* L)
// push userdata containing the DeviceProxy
DeviceProxyWrapper** udata = (DeviceProxyWrapper**)lua_newuserdata(L, sizeof(DeviceProxyWrapper*));
*udata = new DeviceProxyWrapper(name);
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);
@ -115,29 +161,40 @@ 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:index(%s)", name);
LUT_LOG(TRACE, "LUA API DeviceProxy(%s):index(%s)", dev_name.c_str(), name);
std::vector<std::string>* cmdlist = udata->dev->get_command_list();
if(std::count(cmdlist->begin(), cmdlist->end(), name))
try
{
// 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);
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", full_name.c_str());
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;
}
else
catch(Tango::DevFailed e)
{
// 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);
lut_DevFailed(L, e, full_name.c_str());
}
delete cmdlist;
return 1;
}
@ -146,28 +203,38 @@ 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:newindex(%s)", attr_name);
LUT_LOG(TRACE, "LUA API DeviceProxy(%s):newindex(%s)", dev_name.c_str(), attr_name);
std::vector<std::string>* attrlist = udata->dev->get_attribute_list();
if(!std::count(attrlist->begin(), attrlist->end(), attr_name))
try
{
// name is not an attribute
LUT_LOG(ERROR, "Not an attribute: %s", attr_name);
return 0;
}
std::vector<std::string>* attrlist = udata->dev->get_attribute_list();
if(udata->type_map.find(attr_name) == udata->type_map.end())
if(!std::count(attrlist->begin(), attrlist->end(), attr_name))
{
// name is not an attribute
LUT_LOG(ERROR, "Not an attribute: %s", full_name.c_str());
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", full_name.c_str());
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 = pack_attr_data(L, 3, udata->type_map[attr_name], attr_name);
udata->dev->write_attribute(v);
}
catch(Tango::DevFailed e)
{
// 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();
lut_DevFailed(L, e, full_name.c_str());
}
Tango::DeviceAttribute v = pack_attr_data(L, 3, udata->type_map[attr_name], attr_name);
udata->dev->write_attribute(v);
return 0;
}

View File

@ -6,12 +6,14 @@
#include <core/tango.h>
#include <core/lua.h>
#include <core/utils.h>
#include <core/lua/object.h>
#include <core/logging/log.h>
#include <core/tango/attrdata.h>
#include <core/tango/cmddata.h>
#include <core/tango/DevFailed/lut_DevFailed.h>
#define LUT_DEVICEPROXY "lut_DeviceProxy"

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

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

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

@ -0,0 +1,8 @@
#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__ */

View File

@ -1,5 +1,6 @@
local core = require "lutango.core"
local log = require "lutango.lutLog"
local try = require "lutango.try"
local lutObject = {}
@ -20,7 +21,7 @@ function lutObject:__call(...)
}
if self.__type then
o.__obj = core[self.__type].create(...)
o.__obj = try(core[self.__type].create, ...)
end
setmetatable(o, lutObject)
@ -32,10 +33,10 @@ function lutObject:__index(key)
local from_core = core[self.__type][key]
if from_core then
return function(...)
return from_core(self.__obj, ...)
return try(from_core, self.__obj, ...)
end
end
return core[self.__type].index(self.__obj, key)
return try(core[self.__type].index, self.__obj, key)
else return nil end
end
@ -46,7 +47,7 @@ function lutObject:__newindex(key, value)
log(log.level.ERROR, "Cannot write non-attribute: "..key)
return nil
end
core[self.__type].newindex(self.__obj, key, value)
try(core[self.__type].newindex, self.__obj, key, value)
else return nil end
end

24
src/try.lua Normal file
View File

@ -0,0 +1,24 @@
local log = require "lutango.lutLog"
local function default_handler(e)
io.stderr:write("\n=================================== EXCEPTION ===================================\n")
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
io.stderr:write(debug.traceback("", 6))
io.stderr:write("\n=================================================================================\n\n")
end
local function try(...)
local f = arg[1]
table.remove(arg, 1)
local ok, ret = xpcall(function() return f(unpack(arg)) end, default_handler)
return ret
end
return try

View File

@ -1,6 +1,9 @@
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")

View File

@ -6,18 +6,14 @@ local dp = lut.DeviceProxy(arg[1] or "sys/tg_test/1")
local attrlist = dp:get_attribute_list()
for _,v in ipairs(attrlist) do
if v ~= "no_value" and v ~= "throw_exception" then
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("}")
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
print()
else
print("-- Can't handle that yet: "..v)
io.write("}")
end
print()
end