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.
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.
What I want to do is to dynamically stop a function in lua. My code that i tried:
local SaveReal = Thread
local stopped = false
--[[
Thread function runs the lua function
that it includes in a separate thread.
It was created before here
and is trying to be manipulated here.
]]--
Thread = function(func)
SaveReal(function()
while(not stopped) do
func()
end
end)
end
Thread(function()
while(true) do
print("Thread working")
end
end)
Maybe if I could read the contents of the function as a string, I could load it into my manipulative function with load. so the code would not work if my flag is not false.
Lua has something called Coroutines to provide multi-tasking (not multi-threading).
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()
I have the following lua script :
mydata={}
function update(val)
mydata["x"] = val
if (val == 10)
-- Call C-Api(1)
else
--Register callback with C when free or some event happens
register_callback(callme)
end
function callme()
end
Basically I would like to have two instances of this script running in my C program/process with out having to create a new LUA state per script. And I want to call the function update() with val = 10 from the one instance and call the function update() with val = 20 from another instance. From the second instance it registers a callback function and just waits to be called.
Basically the script file is kind of a RULE that i am trying to achieve.
Several events on the system can trigger this rule or script file. I would like to process this rule as per the event that triggered it. There could be multiple events triggering this script to run at the same time. So I need to have multiple instances of this script running differentiated by the kind of event that triggered it.
To Summarize, I want each caller to have separate individual instance of mydata
I would like to achieve something like this. I read some where that we should be able to run multiple instances of a lua script with out having to create a new lua instance by loading a new environment before loading the script
But I am not able to find the exact details.
Could some body help ?
While I'm still not sure what exactly you are trying to achieve, but if you want to have two instances of the same function that keep the data they use private, you just need to create a closure and return an anonymous function that your C code will use.
Something like this should work:
function createenv(callme)
local mydata={}
return function (val) -- return anonymous function
mydata["x"] = val
if (val == 10)
-- Call C-Api(1)
else
--Register callback with C when free or some event happens
register_callback(callme)
end
end
end
Now in one part of your (C or Lua) code you can do:
local update = createenv(function() --[[do whatever]] end)
update(10)
And then in another part you can do:
local update = createenv(function() --[[do something else]] end)
update(20)
And they should have nothing in common between each other. Note that they still shared the same Lua state, but their instances of mydata will be independent of each other.
Why can't this Lua function using a self ":" be marked "local" without getting:
'(' expected near ':'
That is, in the code below things work. But why can't I make the "scene:createScene" function local (as I get the above-mentioned error when trying).
I note the listener functions need to be made local else I have struck cross-scene issues at times in storyboard. These can be marked local and work fine.
SceneBase = {}
function SceneBase:new()
local scene = Storyboard.newScene()
local function returnButtonTouch_Listener (event)
-- code here
end
function scene:createScene( event ) -- WHY CAN'T THIS BE LOCAL???
-- code here
end
return scene
end
return SceneBase
That is why can't the function line read:
local function scene:createScene( event )
function scene:createScene(event) ... end
Is syntax sugar for:
scene.createScene = function(self, event) ... end
Which is syntax sugar for:
scene["createScene"] = function(self, event) ... end
You want to do:
local scene["createScene"] = function(self, event) ... end
Which makes no sense.
Another way of putting it: local is a qualifier for a variable which makes it local rather than global. What variable would you be qualifying with local function scene:createScene( event )?
createScene is not a variable, it's a key in the table scene.
Actually, that's a bit misleading. When you say:
foo = 10
Without qualification, foo becomes global, which is to say it's stored in the global state like this:
_G.foo = 10;
Which of course means the same as this:
_G["foo"] = 10;
When you use the keyword local, it doesn't get stored in a table, it ends up stored in a VM register, which is both faster and has more tightly constrained scope.
When you write either of these:
function foo.bar() end
function foo:bar() end
You are explicitly storing the function value in a table (foo). Those statements are exactly equivalent to these, respectively:
foo["bar"] = function() end
foo["bar"] = function(self) end
I note the listener functions need to be made local
What do you mean by that? In Lua, a function is a function is a function. It's just another value, like a string or number. Whether it's stored in a global, table, local, or not stored at all is irrelevant.
local foo = print
_G["zap"] = foo
doh = zap
t = { zip = doh }
t.zip("Hello, World") -- Hello, World
assert(print == foo
and zap == foo
and zap == doh
and t.zip == doh)
Here we pass the print function around. It's all the same function, and as long as we have a reference to it we can call it.
I don't know Corona, but I'm guessing that event handlers are not specified by naming convention of locals. You need to register it as an event handler. For instance, according to this video a Button object has an onEvent field which is set to the handler for that button.