lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Before I decide on the approach I'm going to take with our 3rd party network communications API, I wanted to see if anyone had any other solutions to the problem I'm attempting to solve. First I'll explain our scripting framework since any solution will need to work inside of that.
 
We have an internal C++ based control engine( control in the control systems sense ). The user can define scripts which have inputs and outputs, and can be wired to controls. The script is run once at system initialization and the user attaches functions to controls that are called when the control changes value. Here's an example script-
 
function SumAndCount()
  sum = 0
  count = 0
  for i,v in ipairs(Controls.Inputs) do
    sum = sum + v.Position
    count = count + 1
  end
  return sum, count
end
 
-- average all inputs
function avr()
  s, c = SumAndCount()
  Controls.Outputs[1].Position = s/c
end
 
-- iterate all inputs and set up the event handler
-- everytime any control input changes the output
-- will be set to the average value
for i,v in ipairs(Controls.Inputs) do
  v.EventHandler = avr
end
 
The event handlers are called any time a control changes and are called in the context of our main control processing thread - they need to return relatively quickly. We also have a capability for the user to define a function that gets called on a timer which has the same constraints - it can't block the execution.
 
The goal is to allow our users to communicate with 3rd party hardware via UPD, TCP/IP and RS-232. Common usage might be to watch an input value, and if it changes, send out a value on the network and verify the result. Something like
 
function SendToNet()
  socket:Connect("123.123.123.123", 222 )
  socket:SendString("test")
  retVal = socket:GetString()
  if retVal == "OK" then
    Controls.Outputs[1].Color = "Green"
  else
    Controls.Outputs[1].Color = "Red"
  end
end
 
Controls.Inputs[1].EventHandler = SendToNet
 
Obviously a script like that wouldn't directly work in our framework - each socket call could block for quite a while which would wedge our control system.
 
The ideal solution is to determine a way to use LuaSockets in our framework. Not only does this mean less development work on our end but it opens up a lot of communications possibilites that we likely wouldn't have. Given our current framework, it seems like it might be possible to use our Timer, coroutines and yield to cobble something together that would work with LuaSockets. Note the following is a mishmash of pseudocode and semi-real code from LuaSockets.
 
function WaitForSend()
  -- how well will this work considering the docs say 'The function may return
  -- a socket as writable even though the socket is not ready for sending'?????
  while true do 
    r, w, e = socket.select(nil, { socket }, 0 )
    if w then break
    coroutine.yield()
  end
end
 
function WaitForReceive()
  while true do
    r, w, e = socket.select( {socket}, nil, 0 )
    if w then break
    coroutine.yield()
  end
end
 
function SendToNet()
  -- connect with 0 timeout and wait until the connection is ready
  socket:Connect("123.123.123.123", 222, 0 )
  WaitForSend()
  -- send our data. I assume this blocks but hopefully not too long
  socket:send("test")
  response = ""
  while true do
    WaitForReceive()
    -- use getstats() and receive to fill out our response buffer until we get a LF and then break
  end
end
 
co = coroutine.create(SendToNet)
 
function TimerTick()
  coroutine.resume(co)
end
 
Timer.EventHandler = TimerTick
Timer.Start(.03) -- tick every 30 ms
 
On the surface this seems like it might work. The biggest concern is that the LuaSocket documentation mentions that there are cases where the timouts might be ignored ( DNS resolution, etc ). Also, since the socket code would have to be carefully crafted to work in our framework it doesn't seem like it would be trivial to leverage libraries that used LuaSocket ( like the SNMP one ).
 
Given the complexity of the code and the unknowns, I don't think the above solution makes sense. Can anyone suggest another approach that would work with our framework?
 
Thanks-
 
John