I am trying out the Elecrow ESP8266 and using the NodeMCU firmware (nodemcu_integer_0.9.6-dev_20150704.bin). My connection code looks like this:
function foo()
conn = net.createConnection(net.TCP, 0)
conn:on("connection", function()
text = "some text\r\n"
conn:send(text)
end)
conn:connect(5000,"192.168.240.1")
end
This is in a function. My first question is when do we exit out of this function? Do I have to explicitly have an 'exit' statement? I realize NodeMCU is event-driven, and the call to connect is after the logic handling a 'connection' (at which point I send something). I'm ok with that but I wonder how and when we get out of 'foo'.
The other thing is, how do I implement a timeout on this? I'd want to timeout and exit when that occurs.
Thanks for any tips.
In this piece of code, between function foo() and end, you are defining the function foo () not executing it at this moment.
This code will be executed when this function is called in another code with a foo()
When you call foo () and the foo () code is executed, When you call foo () and the foo () code is executed, you first
conn = net.createConnection(net.TCP, 0)
create (in the present) a socket and assign it to the variable conn. conn is the soket from that moment.
Then,
conn:on("connection", function()
text = "some text\r\n"
conn:send(text)
end)
you assign a callback function that will be executed in the (future) event when the socket achieves a connection.
Then,
conn:connect(5000,"192.168.240.1")
you ask the plug to try a connection and the execution of the function foo () ends (and foo () returns)
In an imaginary time line things could go like this.
When the interpreter reads the code [function foo() ... end], the function foo () is defined, but not executed.
0us foo() The foo() code starts executing because we call foo()
20us net.create... The socket is created
40us conn:on... Certain callback function is asignated to de socket
60us conn:connect.. The socket starts an attempt to connect
65 us The foo() function ends and returns, and "another code" is executed
120 us The socket achieves the connection and the callback function is triggered
125 us The callback code:
text = "some text\r\n"
conn:send(text)
is executed in parallel with "another code"
The future event "socket connected" fires, in the future, the callback asigned, in the present, with conn:on()
Related
Following instructions on https://nodemcu.readthedocs.io/en/release/modules/tmr/#tobjcreate
I am trying to create a timer in my Lua script which will execute a function every 10 seconds. Sample timer from my script:
mytimer = tmr.create
mytimer:register(10000, tmr.ALARM_AUTO, my_function() end)
mytimer:start()
When I execute my script I'm getting a syntax error:
'=' expected near 'mytimer'
What am I doing wrong here?
Thanks
Well instead of asking here, a good starting point would have been to compare your code vs the code example from the documentation you linked:
local mytimer = tmr.create()
mytimer:register(5000, tmr.ALARM_SINGLE, function (t) print("expired"); t:unregister() end)
mytimer:start()
Example: local mytimer = tmr.create()
You mytimer = tmr.create
You're missing the call operator here. Not making mytimer local is bad practice but won't give you an error.
Example: mytimer:register(5000, tmr.ALARM_SINGLE, function (t) print("expired"); t:unregister() end)
You: mytimer:register(10000, tmr.ALARM_AUTO, my_function() end)
I don't know what my_function is. The end doesn't belong here unless you're defining a function in place. then it should look like in the example. Your version would only be ok without the end and if my_function() would return a function value.
function (t) print("expired"); t:unregister() end defines an anonymous function. This resolves to a function value that is used as an argument for the callback parameter of the register function.
You could also do it like:
local callback = function (t) print("expired"); t:unregister() end
mytimer:register(5000, tmr.ALARM_SINGLE, callback)
Anything else is described in the manual.
Using a dart stream for the 1st time. In the following code, while stepping through it in VSCODE, jumps from the tranform result to the final bracket. It appears to not execute any of the listen callbacks. How do I resolve this?
Future<void> addListsFileToDb(File file) async {
file.openRead().transform(utf8.decoder).listen(
(String value) => print(value),
onError: (error) => print(error),
onDone: () => print("done"));}
Streams (like futures) are asynchronous. When you call listen, you tell the stream to start working, and set up some callbacks to get called when the stream has a value available ... and then it's done.
Later, potentially much later depending on what the stream is doing, the stream will have generated its first value. At that point it will generate a data event, which will call the data callback/handler (here (String value) => print(value)).
Until then, program execution continues normally, so skipping to the end of the listen call immediately is correct and expected behavior, the listen call completes immediately and doesn't call any of the callbacks yet.
I have a custom Lua interpreter executable with some basic socket functionality built in. It's not Luasocket, and as much as I would like to be using Luasocket here, I can't (so please don't suggest it as an answer).
The socket API that I'm working with relies on asynchronous closures to signal that a network operation is complete. So, in the code below, socketConnect() returns immediately and then onConnect() is called later on when the connection is complete.
local function onConnect(cookie, err, sock)
print("Connected!")
end
local function connect(host, port)
local success, err = socketConnect(host, port, onConnect)
print("Connecting...")
end
So, here's the question. I want to make the connect() function block until the onConnect() closure is called. I'm pretty new at Lua, but I'm hoping that coroutines might be helpful here?
EDIT: Here's my attempt at making the function block by using a coroutine:
local connected = false
local function onConnect(cookie, err, sock)
print("Connected!")
connected = true
end
local coroConnect = coroutine.create(
function()
local success, err = socketConnect(m_sHost, m_nPort, onConnect);
while not connected do
coroutine.yield()
end
end
)
local function connect(sHost, nPort)
m_sHost = sHost
m_nPort = nPort
while not coroutine.status(coroConnect) ~= "dead" do
coroutine.resume(coroConnect)
print("Connecting...")
end
end
If you want to use coroutines, something along these lines may work for you (or give you an idea on what to try):
-- this should really be a socket property, but good enough for this example
local connected
local function onConnect(cookie, err, sock)
print("Connected!")
connected = true
end
local function connect(host, port)
connected = false
local success, err = socketConnect(host, port, onConnect)
while not connected do
coroutine.yield()
end
print("Connecting...")
end
If you now create a coroutine from connect function and continue calling that coroutine with coroutine.resume until it's completed (coroutine.status for that coroutine will return 'dead'), you will get the desired result. Obviously, you can move that while loop into socketConnect function itself, which will make is synchronous from the user perspective as it won't return anything until onConnect is executed.
is there a way to stop a lua pcall to a lua function block from mid execution? Im using multiple threads and would be good to cancel a function mid-flight.
The simplest way is to call error('my message') as this will abort the execution and will return nil, 'my message' as the result of pcall(). If you want to abort a running coroutine (or a "main" chunk) from "outside", the only way to do it I know about without modifying Lua VM is to attach a debug hook to coroutine or the main chunk and call error() from that debug hook:
print(1)
local count = 0
debug.sethook(function(event, line)
if count > 1 then error('done', 2) end
count = count + 1
end, "l")
print(2)
print(3)
print("not getting here")
You should see something like this:
1
2
3
script.lua:4: done
In the case of pcall, you will see the parameter of the error() call to be passed as the error message by pcall.
The conditions to check can get quite elaborate; for example, you can check for the hook to be called from a particular function with a certain number of commands executed before aborting.
I have a COM object, which I connect to, and I should recieve an event, which would confirm that connection is established. I write code and test it in F# interactive, and for some reason it wouldn't catch COM events when I use Async.RunSynchronously.
/// This class wraps COM event into F# Async-compatible event
type EikonWatcher(eikon : EikonDesktopDataAPI) =
let changed = new Event<_>()
do eikon.add_OnStatusChanged (fun e -> changed.Trigger true)
member self.StatusChanged = changed.Publish
/// My method
let ``will that connection work?`` () =
let eikon = EikonDesktopDataAPIClass() :> EikonDesktopDataAPI // create COM object
let a = async {
let watcher = EikonWatcher eikon // wrap it
eikon.Initialize() |> ignore // send connection request
let! result = Async.AwaitEvent watcher.StatusChanged // waiting event
printfn "%A" result // printing result
return result
}
// I use either first or second line of code, not both of them
Async.Start (Async.Ignore a) // does not hang, result prints
Async.RunSynchronously (Async.Ignore) a // hangs!!!
/// Running
``will that connection work?`` ()
At the same time, code works perfectly well with RunSynchronously when I insert it into console app.
What should I do so that to prevent that nasty behavior?
The code we write under within a single Thread (as in STA) feels like it is made of independant pieces each having their own life, but this is actually a fallacy : everything is mediated under a common event loop, which "linearizes" the various calls.
So everything we do, unless explicitely spoecified otherwise, is essentially single threaded and you can not wait for yourself without creating a deadlock.
When you specify Async.Start it does start a new, independant computation which runs on its own, a "thread".
Whereas When you call runsynchronously, it awaits on the same 'thread'.
Now if the event you are waiting, which feels like an independant thing, is actually 'linearized' by the same event loop, you are actually waiting for yourself, hence the deadlock.
Something useful if you want to wait "asynchronously", (aka wait for an event, but not actually block and leave the opportunity for any other task to perform work) you can use the following code within your async block :
async {
....
let! token = myAsyncTask |> Async.StartChild
let! result = token
....
}