-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathluaZmqRemoteApi.lua
More file actions
126 lines (111 loc) · 4.02 KB
/
luaZmqRemoteApi.lua
File metadata and controls
126 lines (111 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
local sim = require 'sim'
local simZMQ = require 'simZMQ'
local cbor = require 'simCBOR'
local RemoteApiClient = {}
function RemoteApiClient.init(host, port)
host = host or '127.0.0.1'
port = port or 23000
RemoteApiClient.context = simZMQ.ctx_new()
RemoteApiClient.socket = simZMQ.socket(RemoteApiClient.context, simZMQ.REQ)
simZMQ.connect(RemoteApiClient.socket, 'tcp://' .. host .. ':' .. port)
RemoteApiClient.uuid = sim.getStringParam(sim.stringparam_uniqueid)
RemoteApiClient.callbackFuncs = {}
RemoteApiClient.VERSION = 2
end
function RemoteApiClient.cleanup()
simZMQ.close(RemoteApiClient.socket)
simZMQ.ctx_term(RemoteApiClient.context)
end
function RemoteApiClient._send(req)
-- convert a possible function to string, and nil to "_*NIL*_":
if req.args then
local a = {}
for i = 1, #req.args, 1 do
if req.args[i] == nil then
a[i] = '_*NIL*_'
elseif type(req.args[i]) == 'function' then
local funcStr = "f" .. sim.getStringParam(sim.stringparam_uniqueid)
RemoteApiClient.callbackFuncs[funcStr] = req.args[i]
a[i] = funcStr .. "@func"
else
a[i] = req.args[i]
end
end
req.args = a
end
req.uuid = RemoteApiClient.uuid
req.ver = RemoteApiClient.VERSION
local rawReq = cbor.encode(req)
simZMQ.send(RemoteApiClient.socket, rawReq, 0)
end
function RemoteApiClient._recv()
local r, rawResp = simZMQ.recv(RemoteApiClient.socket, 0)
local resp, a = cbor.decode(tostring(rawResp))
return resp
end
function RemoteApiClient._process_response(resp)
local ret = resp.ret
if #ret == 1 then return ret[1] end
if #ret > 1 then return unpack(ret) end
end
function RemoteApiClient.call(func, args)
-- Call function with specified arguments. Is reentrant
RemoteApiClient._send({func = func, args = args})
local reply = RemoteApiClient._recv()
while reply.func do
-- We have a callback or a wait:
if reply.func == '_*wait*_' then
RemoteApiClient._send({func = '_*executed*_', args = {}})
else
local args = {}
if RemoteApiClient.callbackFuncs[reply.func] then
args = RemoteApiClient.callbackFuncs[reply.func](reply.args)
else
funcToRun = _G[reply.func]
if funcToRun then -- we cannot raise an error: e.g. a custom UI async callback cannot be assigned to a specific client
args = funcToRun(reply.args)
end
end
RemoteApiClient._send({func = '_*executed*_', args = args})
end
reply = RemoteApiClient._recv()
end
if reply.err then error(reply.err) end
return RemoteApiClient._process_response(reply)
end
function RemoteApiClient.getObject(name, _info)
local ret = {}
if not _info then _info = RemoteApiClient.call('zmqRemoteApi.info', {name}) end
for k, v in pairs(_info) do
if type(v) ~= 'table' then error('found non table') end
local s = 0
for k_, v_ in pairs(v) do
s = s + 1
if s >= 2 then break end
end
if s == 1 and v.func then
local func = name .. '.' .. k
ret[k] = function(...)
return RemoteApiClient.call(func, {...})
end
elseif s == 1 and v.const then
ret[k] = v.const
else
ret[k] = RemoteApiClient.getObject(name .. '.' .. k, v)
end
end
return ret
end
function RemoteApiClient.require(name)
RemoteApiClient.call('zmqRemoteApi.require', {name})
return RemoteApiClient.getObject(name)
end
function RemoteApiClient.setStepping(enable) -- for backw. comp., now via sim.setStepping
enable = enable or true
return RemoteApiClient.call('sim.setStepping', {enable})
end
function RemoteApiClient.step(wait) -- for backw. comp., now via sim.step
wait = wait or true
RemoteApiClient.call('sim.step', {wait})
end
return RemoteApiClient