Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Nodemcu Firmware
Commits
50b69d84
Commit
50b69d84
authored
Jul 19, 2019
by
Terry Ellison
Committed by
Marcel Stör
Jun 09, 2020
Browse files
Add telnet example
parent
e7c29fe3
Changes
4
Hide whitespace changes
Inline
Side-by-side
lua_examples/telnet/README.md
View file @
50b69d84
...
...
@@ -6,42 +6,19 @@
| 2018-05-24 |
[
Terry Ellison
](
https://github.com/TerryE
)
|
[
Terry Ellison
](
https://github.com/TerryE
)
|
[
telnet.lua
](
./telnet.lua
)
|
The Lua telnet example previously provided in our distro has been moved to this
file
`simple_telnet.lua`
in this folder. This README discusses the version complex
implementation at the Lua module
`telnet.lua`
. The main reason for this complex
alternative is that a single Lua command can produce a LOT of output, and the
telnet server has to work within four constraints:
-
The SDK rules are that you can only issue one send per task invocation, so any
overflow must be buffered, and the buffer emptied using an on:sent callback (CB).
-
Since the interpeter invokes a node.output CB per field, you have a double whammy
that these fields are typically small, so using a simple array FIFO would rapidly
exhaust RAM.
-
For network efficiency, the module aggregates any FIFO buffered into sensible
sized packet, say 1024 bytes, but it must also need to handle the case when larger
string span multiple packets. However, you must flush the buffer if necessary.
-
The overall buffering strategy needs to be reasonably memory efficient and avoid
hitting the GC too hard, so where practical avoid aggregating small strings to more
than 256 chars (as NodeMCU handles
\<
256 using stack buffers), and avoid serial
aggregation such as buf = buf .. str as this hammers the GC.
So this server adopts a simple buffering scheme using a two level FIFO. The
`node.output`
CB adds records to the 1st level FIFO until the #recs is
\>
32 or the
total size would exceed 256 bytes. Once over this threashold, the contents of the
FIFO are concatenated into a 2nd level FIFO entry of upto 256 bytes, and the 1st
level FIFO cleared down to any residue.
The sender dumps the 2nd level FIFO aggregating records up to 1024 bytes and once this
is empty dumps an aggrate of the 1st level.
Lastly remember that owing to architectural limitations of the firmware, this server
can only service stdin and stdout. Lua errors are still sent to stderr which is
the UART0 device. Hence errors will fail silently. If you want to capture
errors then you will need to wrap any commands in a
`pcall()`
and print any
error return.
This README discusses the packet marshalling versions of telnet. The first (fifosock)
version was written for SDK 2 implementations, with all of the marshalling imlemented
in Lua; the second (pipe) version uses the latest features added to the SDK 3 version
that have been added to prepare for the
`lua53`
implementation. These exploit the
stdin / stdout pipe functionality and task integration that is now build into the
NodeNMCU Lua core.
There are two nice advantages of this core implementation:
-
Errors are now written to stdout in a spearate task execution.
-
The pipes pretty much eliminate uart and telnet overrun.
Both have the same interface if required into the variable
`telnet`
## telnet:open()
...
...
@@ -64,7 +41,7 @@ Nothing returned (this is evaluted as `nil` in a scalar context).
## telnet:close()
Close a telnet server and release all resources.
Close a telnet server and release all resources.
Also set the variable
`telnet`
to nil to fully reference and GC the resources.
#### Syntax
...
...
lua_examples/telnet/simple_telnet.lua
deleted
100644 → 0
View file @
e7c29fe3
-- a simple telnet server
telnet_srv
=
net
.
createServer
(
net
.
TCP
,
180
)
telnet_srv
:
listen
(
2323
,
function
(
socket
)
local
fifo
=
{}
local
fifo_drained
=
true
local
function
sender
(
c
)
if
#
fifo
>
0
then
c
:
send
(
table.remove
(
fifo
,
1
))
else
fifo_drained
=
true
end
end
local
function
s_output
(
str
)
table.insert
(
fifo
,
str
)
if
socket
~=
nil
and
fifo_drained
then
fifo_drained
=
false
sender
(
socket
)
end
end
node
.
output
(
s_output
,
0
)
-- re-direct output to function s_ouput.
socket
:
on
(
"receive"
,
function
(
c
,
l
)
node
.
input
(
l
)
-- works like pcall(loadstring(l)) but support multiple separate line
end
)
socket
:
on
(
"disconnection"
,
function
(
c
)
node
.
output
(
nil
)
-- un-regist the redirect output function, output goes to serial
end
)
socket
:
on
(
"sent"
,
sender
)
print
(
"Welcome to NodeMCU world."
)
end
)
lua_examples/telnet/telnet.lua
→
lua_examples/telnet/telnet
_fifosock
.lua
View file @
50b69d84
File moved
lua_examples/telnet/telnet_pipe.lua
0 → 100644
View file @
50b69d84
--[[ A telnet server T. Ellison, June 2019
This version of the telnet server demonstrates the use of the new stdin and stout
pipes, which is a C implementation of the Lua fifosock concept moved into the
Lua core. These two pipes are referenced in the Lua registry.
]]
local
M
=
{}
local
modname
=
...
local
function
telnet_session
(
socket
)
local
node
=
node
local
stdout
,
sending
local
function
output_CB
(
opipe
)
-- upval: socket
stdout
=
opipe
local
rec
=
opipe
:
read
(
1400
)
if
rec
and
#
rec
>
0
then
socket
:
send
(
rec
)
end
return
false
-- don't repost as the on:sent will do this
end
local
function
onsent_CB
(
skt
)
-- upval: stdout
local
rec
=
stdout
:
read
(
1400
)
if
rec
and
#
rec
>
0
then
skt
:
send
(
rec
)
end
end
local
function
disconnect_CB
(
skt
)
-- upval: socket, stdout
node
.
output
()
socket
,
stdout
=
nil
,
nil
-- set upvals to nl to allow GC
end
node
.
output
(
output_CB
,
0
)
socket
:
on
(
"receive"
,
function
(
_
,
rec
)
node
.
input
(
rec
)
end
)
socket
:
on
(
"sent"
,
onsent_CB
)
socket
:
on
(
"disconnection"
,
disconnect_CB
)
print
((
"Welcome to NodeMCU world (%d mem free, %s)"
):
format
(
node
.
heap
(),
wifi
.
sta
.
getip
()))
end
function
M
.
open
(
this
,
ssid
,
pwd
,
port
)
local
tmr
,
wifi
,
uwrite
=
tmr
,
wifi
,
uart
.
write
if
ssid
then
wifi
.
setmode
(
wifi
.
STATION
,
false
)
wifi
.
sta
.
config
{
ssid
=
ssid
,
pwd
=
pwd
,
save
=
false
}
end
local
t
=
tmr
.
create
()
t
:
alarm
(
500
,
tmr
.
ALARM_AUTO
,
function
()
if
(
wifi
.
sta
.
status
()
==
wifi
.
STA_GOTIP
)
then
t
:
unregister
()
t
=
nil
print
((
"Telnet server started (%d mem free, %s)"
):
format
(
node
.
heap
(),
wifi
.
sta
.
getip
()))
M
.
svr
=
net
.
createServer
(
net
.
TCP
,
180
)
M
.
svr
:
listen
(
port
or
23
,
telnet_session
)
else
uwrite
(
0
,
"."
)
end
end
)
end
function
M
.
close
(
this
)
if
this
.
svr
then
this
.
svr
:
close
()
end
package.loaded
[
modname
]
=
nil
end
return
M
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment