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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
#!/usr/bin/lua
--[[
Syntax
# lua bobot-server.lua [DEBUG] [connection]*
Parameters:
DEBUG enables debug printing in bobot
connection a list of connection services to attempt. Supported
values in bobot (for now) are usb, serial and chotox
If no connection services are provided, defaults to usb and serial.
Examples:
Start with debug disabled and the dummy chotox service, only:
# lua bobot-server.lua chotox
Start with debug enabled and the serial services only:
# lua bobot-server.lua DEBUG serial
Start with debug disabled and the usb and serial services (same as default):
# lua bobot-server.lua usb serial
--]]
--package.path=package.path..";./bobot_server/?.lua"
local my_path = debug.getinfo(1, "S").source:match[[^@?(.*[\/])[^\/]-$]] or "./"
package.path=package.path..";"..my_path.."bobot_server/?.lua;"
..my_path.."lib/?.lua;"..my_path.."?.lua"
--tcp listening address
local N_PROTOCOLS = 2
local ADDRESS = "*"
local PORT_B = 2009 --B is for bobot
local PORT_H = 2010 --H is for http
local TIMEOUT_REFRESH = 3
local socket = require("socket")
local process = require("bobot-server-process").process
local http_serve = require("bobot-server-http").serve
local bobot = require("bobot")
local set_debug
for i, v in ipairs(arg) do
if v=="DEBUG" then
set_debug=true
table.remove(arg, i)
break
end
end
if set_debug then
bobot.debugprint = print
bobot.debugprint("Debugging messages enabled")
else
bobot.debugprint = function() end
end
local server_b = assert(socket.bind(ADDRESS, PORT_B))
local server_h = assert(socket.bind(ADDRESS, PORT_H))
local recvt={[1]=server_b, [2]=server_h}
devices = {}
local function get_device_name(d)
--print("DEVICENAME", d.module, d.hotplug, d.handler)
local board_id, port_id = '', ''
if #bobot.baseboards>1 then
board_id='@'..d.baseboard.idBoard
end
if d.hotplug then
port_id = ':'..d.handler
end
local n=d.module..board_id..port_id
if not devices[n] then
return n
end
local i=2
local nn=n.."#"..i
while devices[nn] do
i=i+1
nn=n.."#"..i
end
return nn
end
local function read_devices_list()
bobot.debugprint("=Listing Devices")
local bfound
devices={}
for _, bb in ipairs(bobot.baseboards) do
bobot.debugprint("===board ", bb.idBoard)
for _,d in ipairs(bb.devices) do
local regname = get_device_name(d)
devices[regname]=d
devices[#devices+1]=d
d.name=regname
bobot.debugprint("=====module ",d.module," name",regname)
end
bfound = true
end
if not bfound then bobot.debugprint("ls:WARN: No Baseboard found.") end
end
local function split_words(s)
local words={}
for p in string.gmatch(s, "%S+") do
words[#words+1]=p
end
return words
end
local socket_handlers = {}
setmetatable(socket_handlers, { __mode = 'k' })
socket_handlers[server_b]=function()
local client, err=server_b:accept()
if not client then return end
bobot.debugprint ("bs:New bobot client", client, client:getpeername())
table.insert(recvt,client)
socket_handlers[client] = function ()
local line,err = client:receive()
if err=='closed' then
bobot.debugprint ("bs:Closing bobot client", client)
for k, v in ipairs(recvt) do
if client==v then
table.remove(recvt,k)
return
end
end
end
if line then
local words=split_words(line)
local command=words[1]
if not command then
bobot.debugprint("bs:Error parsing line:", line, command)
else
if not process[command] then
bobot.debugprint("bs:Command not supported:", command)
else
if command=="QUIT" and #recvt>N_PROTOCOLS+1 then
client:send("server in use\n")
return
end
local ret = process[command](words) or ""
client:send(ret .. "\n")
end
end
end
end
end
socket_handlers[server_h]=function()
local client, err=server_h:accept()
if not client then return end
bobot.debugprint ("bs:New http client", client, client:getpeername())
client:setoption ("tcp-nodelay", true)
--client:settimeout(5)
table.insert(recvt,client)
socket_handlers[client] = function ()
local ret,err=http_serve(client)
if err=='closed' then
bobot.debugprint ("bs:Closing http client", client)
for k, v in ipairs(recvt) do
if client==v then
table.remove(recvt,k)
return
end
end
end
if ret then
client:send(ret)
end
end
end
function server_refresh ()
local refreshed
for i, bb in ipairs(bobot.baseboards) do
--if bb.refresh and not (bb.comms.type=='serial' and bb.devices) then
if bb.refresh and bb.hotplug then
if not bb:refresh() then
bobot.baseboards[i]=nil
end
refreshed=true
end
end
if refreshed then read_devices_list() end
end
function server_init ()
bobot.init(arg)
read_devices_list()
end
server_init()
bobot.debugprint("Listening...")
-- loop forever waiting for clients
while 1 do
local recvt_ready, _, err=socket.select(recvt, nil, TIMEOUT_REFRESH)
if err=='timeout' then
if #bobot.baseboards==0 then
server_init ()
else
server_refresh ()
end
else
local skt=recvt_ready[1]
socket_handlers[skt]()
end
end
|